क्या अजगर में एक अंतर्निहित पहचान समारोह है?


145

मैं एक ऐसे फंक्शन की ओर इशारा करना चाहता हूं जिसमें कुछ भी नहीं है:

def identity(*args)
    return args

मेरा उपयोग मामला कुछ इस तरह है

try:
    gettext.find(...)
    ...
    _ = gettext.gettext
else:
    _ = identity

बेशक, मैं identityऊपर दिए गए परिभाषित का उपयोग कर सकता हूं , लेकिन एक अंतर्निहित निश्चित रूप से तेजी से चलेगा (और अपने द्वारा शुरू किए गए कीड़े से बचें)।

जाहिर है, mapऔर पहचान के लिए filterउपयोग Noneकरते हैं, लेकिन यह उनके कार्यान्वयन के लिए विशिष्ट है।

>>> _=None
>>> _("hello")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

6
आपका क्या मतलब है map and filter use None for the identity?
मैट फेनविक

15
@ माटफेनविक:map(None, [1, 2, 3])
ग्रेग

6
रिटर्न वैल्यू देखें। आपका आर्ग्स वैरिएबल (इस परिदृश्य में) एक मान का एक क्रम होगा, इसलिए या तो घोषणा में तारांकन छोड़ दें, या इसे वापस करने के लिए अनपैक करें।
डिर्क

11
@GregHewgill: अफसोस की बात है, कि अजगर 3.x में काम नहीं करता है।
एतान फुरमान

6
@GregHewgill मेरा बुरा। मैंने उस डोग से गुगली करने के बाद ले लिया। लेकिन Python2.x doc हमेशा पहले आता है ...
rds

जवाबों:


99

कुछ और शोध करना, कोई नहीं है, 1673203 में एक फीचर पूछा गया था और रेमंड हैटिंगर ने कहा था :

बेहतर होगा कि लोग अपने स्वयं के तुच्छ पास-थ्रू लिखें और हस्ताक्षर और समय की लागत के बारे में सोचें।

तो यह करने के लिए एक बेहतर तरीका वास्तव में है (एक लंबोदर समारोह के नामकरण से बचा जाता है):

_ = lambda *args: args
  • लाभ: किसी भी संख्या में पैरामीटर लेता है
  • नुकसान: परिणाम मापदंडों का एक बॉक्सिंग संस्करण है

या

_ = lambda x: x
  • लाभ: पैरामीटर का प्रकार नहीं बदलता है
  • नुकसान: ठीक 1 स्थिति पैरामीटर लेता है

13
ध्यान दें कि यह एक पहचान समारोह नहीं है।
मार्सिन

1
@Marcin टिप्पणी के लिए धन्यवाद। मैंने किसी को गुमराह न करने के लिए दोनों के फायदे / कमियां जोड़ी हैं। और अब, मुझे वास्तव में विश्वास है कि एक अंतर्निहित कार्य होना चाहिए था जो किसी भी संख्या में मापदंडों को स्वीकार करता है और एक सही पहचान है :)
rds

7
अच्छा उत्तर। हालांकि, कई मापदंडों को लेते समय एक सही पहचान फ़ंक्शन क्या होगा?
मार्सिन

5
@ मारकिन: न तो, जो उसने अपने सवाल में पूछा था, उसके अनुसार जा रहा था।
एथन फुरमान

4
हाँ धन्यवाद, मेरे पास एक तुच्छ lambda x: xपहचान कार्य है जो एक स्ट्रिंग पैरामीटर के लिए काम करता है। @Marcin मैं मैं कर सकता इच्छा lambda *args: *args:-)
आरडीएस

28

एक पहचान समारोह, जैसा कि https://en.wikipedia.org/wiki/Identity_function में परिभाषित है , एक भी तर्क लेता है और इसे अपरिवर्तित लौटाता है:

def identity(x):
    return x

क्या आप जब आप कहते हैं के लिए पूछ रहे हैं आप हस्ताक्षर चाहते def identity(*args)है नहीं कड़ाई से एक पहचान समारोह, जैसा कि आप यह कई तर्क लेना चाहते हैं। यह ठीक है, लेकिन फिर आप एक समस्या को हिट करते हैं क्योंकि पायथन फ़ंक्शन कई परिणाम वापस नहीं करते हैं, इसलिए आपको उन सभी तर्कों को एक वापसी मूल्य में cramming करने का एक तरीका खोजना होगा।

पायथन में "कई मूल्यों" को वापस करने का सामान्य तरीका मूल्यों का एक टपल वापस करना है - तकनीकी रूप से यह एक वापसी मूल्य है लेकिन इसका उपयोग अधिकांश संदर्भों में किया जा सकता है जैसे कि यह कई मान थे। लेकिन यहां ऐसा करने का मतलब है कि आपको मिल जाएगा

>>> def mv_identity(*args):
...     return args
...
>>> mv_identity(1,2,3)
(1, 2, 3)
>>> # So far, so good. But what happens now with single arguments?
>>> mv_identity(1)
(1,)

और उस समस्या को ठीक करना अन्य मुद्दों को जल्दी से देता है, जैसा कि यहां विभिन्न उत्तर दिखाए गए हैं।

इसलिए, संक्षेप में, पायथन में परिभाषित कोई पहचान समारोह नहीं है क्योंकि:

  1. औपचारिक परिभाषा (एकल तर्क फ़ंक्शन) उपयोगी नहीं है, और लिखने के लिए तुच्छ है।
  2. परिभाषा को कई तर्कों में विस्तारित करना सामान्य रूप से अच्छी तरह से परिभाषित नहीं किया गया है, और आप अपने स्वयं के संस्करण को परिभाषित करने से बहुत बेहतर हैं जो आपके विशेष परिस्थिति के लिए आवश्यक तरीके से काम करता है।

आपके सटीक मामले के लिए,

def dummy_gettext(message):
    return message

लगभग निश्चित रूप से आप क्या चाहते हैं - एक फ़ंक्शन जिसमें समान कॉलिंग कन्वेंशन है और जैसा gettext.gettextकि रिटर्न देता है, जो अपने तर्क को अपरिवर्तित लौटाता है, और स्पष्ट रूप से यह वर्णन करने के लिए नामित किया जाता है कि यह क्या करता है और इसका उपयोग करने का इरादा कहां है। अगर प्रदर्शन यहाँ एक महत्वपूर्ण विचार होता तो मैं बहुत हैरान होता।


मैं नहीं देखता कि आप क्या जवाब देते हैं "उस समस्या को ठीक करने से अन्य समस्याएँ आती हैं, जैसा कि उत्तर ने दिखाया है"। विशेष रूप से, यह उपयोग करने के लिए पर्याप्त है id= lambda *args: args if len(args)>1 else args[0]
मैक्स

21

तुम्हारा काम ठीक रहेगा। जब मापदंडों की संख्या ठीक हो जाती है तो आप इस तरह एक अनाम फ़ंक्शन का उपयोग कर सकते हैं:

lambda x: x

8
आप इसे वैरग के साथ भी कर सकते हैं lambda *args: args:। यह वास्तव में एक शैलीगत पसंद है।

मुझे दूसरा बेहतर लगता है, क्योंकि यह किसी भी तरह के तर्क देता है।
rds

4
@delnan @rds - *argsसंस्करण का एक अलग रिटर्न प्रकार है, इसलिए वे एकल-तर्क मामले के लिए भी समान नहीं हैं।
मार्सिन

8
@delnan: आपने कहा कि यह एक शैलीगत पसंद है, जिसका गलत अर्थ है कि दो रूपों के शब्दार्थ में कोई अंतर नहीं है।
मार्सिन

1
@ मारकिन: यह दुर्भाग्यपूर्ण है अगर मैंने ऐसा किया है। मेरा मतलब इस तरह के सरल कार्यों के लिए defऔर उनके बीच चयन lambdaकरना था।

7

पायथन में कोई अंतर्निहित पहचान फ़ंक्शन नहीं है। हास्केल के idकार्य की एक नकल होगी:

identity = lambda x, *args: (x,) + args if args else x

उदाहरण उपयोग:

identity(1)
1
identity(1,2)
(1, 2)

चूंकि identityदिए गए तर्कों को वापस करने के अलावा कुछ भी नहीं है, मुझे नहीं लगता कि यह एक देशी कार्यान्वयन की तुलना में धीमा है।


यह उस कॉल का निर्माण है जिसमें समय लगता है, भले ही आप उस सेटअप के पूरा होने के बाद क्या करें।
chepner

@chepner क्या आप और अधिक विस्तार से बता सकते हैं कि आपका क्या मतलब है? देशी फ़ंक्शन के लिए कॉल का निर्माण भी किया जाना चाहिए, है ना? क्या यह निर्माण एक गैर-देशी फ़ंक्शन के लिए कॉल निर्माण से अधिक तेज़ी से किया गया है?
सर्जियोकोलनिकोव

1
उपयोगकर्ता-निर्धारित कार्य करने के लिए एक कॉल महंगी के रूप में कम से कम एक फोन के रूप में निर्मित एक समारोह है, और शायद अधिक इसलिए है क्योंकि एक बार आप उपयोगकर्ता परिभाषित समारोह कहा जाता है, और कुछ भी यह आह्वान कर सकते हैं करने के लिए है और अधिक उपयोगकर्ता परिभाषित या अंतर्निहित कार्यों में।
चेपनर

6

नहीं, वहाँ नहीं है।

ध्यान दें कि आपका identity:

  1. मेमने के बराबर है * आर्ग्स: आर्ग्स
  2. विल अपनी पेटी - यानी

    In [6]: id = lambda *args: args
    
    In [7]: id(3)
    Out[7]: (3,)

इसलिए, lambda arg: argयदि आप सही पहचान फ़ंक्शन चाहते हैं, तो आप इसका उपयोग कर सकते हैं ।

एनबी: यह उदाहरण अंतर्निहित idफ़ंक्शन को छाया देगा (जिसका उपयोग आप शायद कभी नहीं करेंगे)।


1
ध्यान दें कि आईडी एक अंतर्निहित फ़ंक्शन है, और यह स्निपेट इसे अधिलेखित कर देगा।
11:97 पर Arnie97

@ Arnie97 मेला! मैं भूल गया थाid
मार्सिन

4

यदि गति मायने नहीं रखती है, तो इसे सभी मामलों को संभालना चाहिए:

def identity(*args, **kwargs):
    if not args:
        if not kwargs:
            return None
        elif len(kwargs) == 1:
            return  next(iter(kwargs.values()))
        else:
            return (*kwargs.values(),)
    elif not kwargs:
        if len(args) == 1:
            return args[0]
        else:
            return args
    else:
        return (*args, *kwargs.values())

उपयोग के उदाहरण:

print(identity())
None
$identity(1)
1
$ identity(1, 2)
(1, 2)
$ identity(1, b=2)
(1, 2)
$ identity(a=1, b=2)
(1, 2)
$ identity(1, 2, c=3)
(1, 2, 3)

1

एकल-तर्क फ़ंक्शन का स्टब

gettext.gettext(ओ पी के उदाहरण उपयोग के मामले) एक एकल तर्क स्वीकार करता है, message। यदि किसी को इसके लिए एक स्टब की आवश्यकता है, तो ( ) के [message]बजाय वापस जाने का कोई कारण नहीं है । इस प्रकार दोनोंmessagedef identity(*args): return args

_ = lambda message: message

def _(message):
    return message

पूरी तरह से स्वस्थ।

... लेकिन एक अंतर्निहित निश्चित रूप से तेजी से चलेगा (और मेरे द्वारा शुरू किए गए कीड़े से बचें)।

ऐसे तुच्छ मामले में कीड़े मुश्किल से प्रासंगिक हैं। पूर्वनिर्धारित प्रकार के एक तर्क के लिए, कहें str, हम str()स्वयं को एक पहचान समारोह के रूप में उपयोग कर सकते हैं ( स्ट्रिंग इंटर्निंग के कारण यह वस्तु पहचान को भी बनाए रखता है, idनीचे नोट देखें) और लंबोदर समाधान के साथ इसके प्रदर्शन की तुलना करें:

$ python3 -m timeit -s "f = lambda m: m" "f('foo')"
10000000 loops, best of 3: 0.0852 usec per loop
$ python3 -m timeit "str('foo')"
10000000 loops, best of 3: 0.107 usec per loop

एक सूक्ष्म अनुकूलन संभव है। उदाहरण के लिए, निम्नलिखित साइथन कोड:

test.pyx

cpdef str f(str message):
    return message

फिर:

$ pip install runcython3
$ makecython3 test.pyx
$ python3 -m timeit -s "from test import f" "f('foo')"
10000000 loops, best of 3: 0.0317 usec per loop

बिल्ड-इन ऑब्जेक्ट आइडेंटिटी फंक्शन

idअंतर्निहित फ़ंक्शन के साथ एक पहचान फ़ंक्शन को भ्रमित न करें जो किसी ऑब्जेक्ट की 'पहचान' लौटाता है ( ==ऑपरेटर के साथ तुलना में उस ऑब्जेक्ट के मूल्य के बजाय उस विशेष वस्तु के लिए एक विशिष्ट पहचानकर्ता का अर्थ है ), सीपीथॉन में इसका मेमोरी एड्रेस।


एक 40% स्पीडअप "इसके लायक नहीं लगता है"? ऐसे मामलों में जहां पहचान एक ऐसे फ़ंक्शन के लिए "डिफ़ॉल्ट फ़िल्टर" के रूप में कार्य करती है, जो चलता है, कहते हैं, एक बार प्रति 10,000x10,000 पिक्सेल छवि पर चैनल (शायद हर दिन नहीं, लेकिन निश्चित रूप से असामान्य नहीं), यह 25 और 9 के बीच का अंतर है निष्पादन समय के सेकंड! बावजूद, आप साइथन उदाहरण के लिए धन्यवाद।
9999 साल जूल

@ 9999 वर्ष से मैं सहमत हूं। मैंने योग्य टिप्पणी को हटा दिया है। उत्तर में सुधार के लिए भी धन्यवाद। मैंने आपके ऊपर कुछ छोटे बदलाव किए हैं।
साज

यदि आपके पास 10,000x10,000 पिक्सेल छवि है, तो मैं दृढ़ता से सदिश संचालन का उपयोग करने की सलाह दूंगा, जैसे कि खसखस। यह तेज़ होगा, रास्ता कम मेमोरी का उपयोग करेगा, और साइथन कोड लिखने की आवश्यकता नहीं होगी।
एंथनीबेल

-2

धागा बहुत पुराना है। लेकिन फिर भी यह पोस्ट करना चाहता था।

तर्कों और वस्तुओं दोनों के लिए एक पहचान विधि का निर्माण संभव है। नीचे दिए गए उदाहरण में, ObjOut ObjIn के लिए एक पहचान है। ऊपर दिए गए अन्य सभी उदाहरणों में तानाशाह ** कवारों से निपटा नहीं है

class test(object):
    def __init__(self,*args,**kwargs):
        self.args = args
        self.kwargs = kwargs
    def identity (self):
        return self

objIn=test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n')
objOut=objIn.identity()
print('args=',objOut.args,'kwargs=',objOut.kwargs)

#If you want just the arguments to be printed...
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().args)
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().kwargs)

$ py test.py
args= ('arg-1', 'arg-2', 'arg-3', 'arg-n') kwargs= {'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}
('arg-1', 'arg-2', 'arg-3', 'arg-n')
{'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}

यह एक संदर्भ की तरह लगता है, यदि हां, तो यह कहां से है?
जेफ पुकेट

@JeffPuckettII मैंने आपके प्रश्न का पालन नहीं किया। क्या आप पूछ रहे हैं कि क्या नई वस्तु एक संदर्भ है?
सूद

आपने "एक पहचान बनाने के लिए संभव है ..." के लिए एक ब्लॉकक्वाइट हाइलाइट का उपयोग किया था, जिसका अर्थ एक अन्य स्रोत से एक संदर्भ है। अगर ये आपके अपने शब्द हैं, तो मैं आपको इसे एक उद्धरण के रूप में उजागर नहीं करने का सुझाव दूंगा। वास्तव में कोई बड़ी बात नहीं है। लेकिन अगर यह किसी अन्य स्रोत से एक उद्धरण है, तो आपको इसका संदर्भ शामिल करना चाहिए।
जेफ पकेट

आप मूल प्रश्न map(identity, [1, 2, 3])रिटर्न का जवाब कैसे देते हैं [1, 2, 3]?
आरडीएस

class test1(object): def __init__(self,*args,**kwargs): self.args = args self.kwargs = kwargs def identity (self): return self.args print(test1([1,2,3]).identity())-> परिणाम: ([1, 2, 3],)
सूद
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.