2010-07-07 12 views
6

विफल हो सकता है शायद मुझे यह पूरी तरह से गलत लगे लेकिन मैं लैम्ब्डा कॉलिंग @classmethod के साथ कुछ अजीब मुद्दों में भाग गया।लैम्ब्डा कॉलिंग @classmethod

मैं निम्नलिखित वर्ग है:

class MyClass: 
    LAMBDA = lambda: MyClass.ClassMethod() 

    @classmethod 
    def ClassMethod(cls): 
    pass 

लेकिन यह विफल रहता है जब भी लैम्ब्डा के साथ कहा जाता है:

TypeError: unbound method <lambda>() must be called with MyClass instance as first argument (got nothing instead) 

मुझे समझ नहीं आता वास्तव में यह क्यों इतना है। मैंने पहले से ही काम करने की कोशिश कर कुछ समय बिताया है। मुझे उस लैम्ब्डा द्वारा आबादी वाले कुछ वर्ग विशेषताओं की आवश्यकता है और कक्षा में आत्म-संदर्भ देने के लिए स्पष्ट रूप से संभव नहीं है।

+0

एफवाईआई, यह पायथन 3 पर काम करता है, लेकिन पायथन 2 पर नहीं। – kennytm

+0

@ केनीटीएम, यह संयोग से पायथन 3 पर काम करता है। पायथन 3 बाध्य विधि से छुटकारा पा लिया और बस कार्य को वापस कर देता है। यद्यपि यह एक अच्छा डिज़ाइन निर्णय है, लेकिन यह वैचारिक रूप से गलत है, ताकि गलत स्थिरता बनाने के लिए इसका उपयोग किया जा सके। –

उत्तर

2

आप को समझना चाहिए, जो आपके कोड वास्तव में

class MyClass: 

    def LAMBDA(): 
    return MyClass.ClassMethod() 

    @classmethod 
    def ClassMethod(cls): 
    pass 

के बराबर आप, तो, जाहिरा तौर पर यह MyClass.LAMBDA() की तरह कहते हैं। लेकिन देखो, लैम्ब्डा एक उदाहरण विधि है। और आप इसे वास्तविक उदाहरण के बिना बुला रहे हैं।

आप वास्तव में क्या करने की कोशिश कर रहे हैं?

मुझे लगता है कि यदि आप लैम्ब्डा निर्माण के लिए नाम दे रहे हैं, तो आप इसे 'सामान्य' तरीका - def घोषित कर सकते हैं। मेरे अनुभव से, लैम्बस का उपयोग करते समय केवल कुछ अलग मामलों में कोड गुणवत्ता में योगदान होता है।

+0

LAMBDA एक * वर्ग सदस्य * है यदि इस तरह परिभाषित किया गया है। 'लैम्ब्डा' आपको विचलित न होने दें। 'LAMBDA = 4' पर विचार करें। – kennytm

+0

बाह, 'रिटर्न' की कमी एक असली शर्म की बात थी – shylent

+2

@ केनीटीएम, "कक्षा सदस्य" पायथन शब्दावली नहीं है, इसलिए यह नाइटपिक पर चुनने के लिए एक अजीब मंच की तरह लगता है। जब शीतल कहता है कि यह एक विधि है, तो इसका मतलब है कि हम लगातार ऐसा करते हैं: वह अर्थपूर्ण चीज़ के बारे में बात कर रहा है, नाम नहीं। –

2

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

दोहराने के लिए, LAMBDA = lambda: MyClass.ClassMethod()def LAMBDA(): return MyClass.ClassMethod() से अलग नहीं है। बाद के मामले में, यह और अधिक स्पष्ट है कि आपके पास टूटी हुई विधि परिभाषा है। एक लैम्ब्डा फ़ंक्शन और एक डीफ़ फ़ंक्शन सटीक उसी प्रकार के ऑब्जेक्ट का निर्माण करता है, और पायथन उन्हें लुकअप समय पर उसी नियम के साथ विधियों में बदल देता है।

मुझे लगता है कोड आप चाहते हो सकता है

class MyClass(object): 
    @classmethod 
    def ClassMethod(cls): 
     pass 
MyClass.LAMBDA = MyClass.ClassMethod 

या

class MyClass(object): 
    @classmethod 
    def ClassMethod(cls): 
     pass 

    @classmethod 
    def LAMBDA(cls): 
     return cls.ClassMethod() 

(नोट: यह पिछले एक एक लैम्ब्डा के रूप में आप मूल रूप से किया था के साथ लिखा जा सकता है, लेकिन करने के लिए कोई कारण नहीं है। मैं व्यक्तिगत रूप से मेरे किसी भी कोड में = lambda का उपयोग कभी नहीं करेगा। यह भी ध्यान दें कि ClassMethod और LAMBDA सामान्य पायथन पूंजीकरण शैली नियमों का पालन नहीं करते हैं।)

0

मुझे उस लैम्ब्डा द्वारा आबादी वाले कुछ वर्ग विशेषताओं की आवश्यकता है और कक्षा में आत्म-संदर्भ देने के लिए स्पष्ट रूप से संभव नहीं है।

लेकिन अपने दिए गए कोड से, सभी लैम्ब्डा जब यह कहा जाता है क्या करेंगे ही फोन MyClass.ClassMethod(), विधि populating कर जिसका मतलब है कि है ClassMethod (यह निश्चित रूप से, है, यह सोचते हैं कि ClassMethod के शरीर वास्तव में नहीं है वह एकमात्र pass आपने दिखाया है, क्योंकि यदि यह सब कर रहा है तो यह व्यर्थता में एक अभ्यास है)।जब तक आपके कोड का कोई पहलू न हो जो आपको किसी भी चीज़ के लिए इसका उपयोग करने से पहले कक्षा का जिक्र करने से रोकता है, तो आप वर्ग परिभाषा के बाद MyClass.ClassMethod() क्यों नहीं कॉल कर सकते?

और यदि आप परिभाषा के अंदर कक्षा के गुणों को संशोधित करने का प्रयास कर रहे हैं (यानी, किसी भी तरीके/कार्यों/जो कुछ भी के बाहर, MyClass की परिभाषा के भीतर LAMBDA को कॉल करना), तो आप इसे देखना चाहेंगे दस्तावेज के अनुभाग metaclasses के बारे में।

एक तरफ ध्यान दें, यदि आप कक्षा में विशेषताओं को असाइन करना चाहते हैं, तो आपको कक्षा के शरीर के भीतर भी ऐसा करने की आवश्यकता नहीं है।

>>> class cls(object): # or just "class cls:" 
...  pass 
... 
>>> cls.value = 10 
>>> cls.name = 'class' 
>>> cls.value 
10 
>>> cls.name 
'class' 
>>> dir(cls) 
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'name', 'value'] 
1

इसके लिए एक और सीधा समाधान है। शायद यह सबसे साफ चीज नहीं है, लेकिन मुझे लगता है कि यह वही है जो आप सोच रहे थे। मैं बस एक ही स्थिति में खुद भाग गया। आप जानबूझ कर staticmethod() के साथ इसे अनइंड कर सकते हैं।

def bar(): return 0 

class foo(object): 
    x = lambda:bar() 
    @classmethod 
    def grok(klass): 
    return klass.x() 

foo().grok() 

Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "<console>", line 4, in grok 
TypeError: unbound method <lambda>() must be called with foo instance as first argument (got nothing instead) 

और थोड़ा समायोजित संस्करण:

def bar(): return 0 

class foo(object): 
    x = staticmethod(lambda:bar()) 
    @classmethod 
    def grok(klass): 
    return klass.x() 

foo().grok() 

0 

ध्यान दें कि ऊपर के दोनों भी हो:

x = bar 

इसके बजाय

यहाँ गलत संस्करण है। मैं सिर्फ लैम्ब्डा को प्रश्न के सीधी प्रतिक्रिया के रूप में शामिल कर रहा था। उपरोक्त सभी सुझाव भी काम करते हैं, यह जितना संभव हो सके कोड को बदलने का एक सीधा तरीका है।

क्यों कोई भी उपरोक्त काम को लैम्ब्डा के साथ क्यों बनाना चाहेगा? मेरे मामले में, मैं एक फैक्ट्री क्लास बना रहा था जिसमें ईवेंट हैंडलर थे जो कभी-कभी जानकारी प्राप्त करने के लिए कक्षा-व्यापी डेटा का उपयोग करते थे, और इनमें से कुछ जानकारी मूल्य-या-कॉल करने योग्य प्रकृति थी। (यह एक Django रूप के लिए था।) तो "कॉल करने योग्य" उपयोगकर्ता द्वारा सौंपा गया एक सीधे लैम्ब्डा था, जिसे self.value() या klass.value() के साथ बुलाया जाना था, लेकिन value एक अनबाउंड फ़ंक्शन (लैम्ब्डा या अन्यथा) था।

संबंधित मुद्दे