2015-11-20 6 views
12

दोनों अजगर 2 और अजगर 3 कोड में: त्रुटि Foo object is not callable रूपउदाहरण के लिए '__call__` विधि को गतिशील रूप से क्यों नहीं जोड़ा जाएगा?

class Foo(object): 
    pass 

f = Foo() 
f.__call__ = lambda *args : args 

f(1, 2, 3) 

रिटर्न। ऐसा क्यों होता है?

पीएस: पुरानी शैली के वर्गों के साथ यह अपेक्षा के अनुसार काम करता है।

पीपीएस: यह व्यवहार इरादा है (स्वीकृत उत्तर देखें)। एक कार्य-आसपास के रूप में कक्षा स्तर पर __call__ को परिभाषित करना संभव है जो केवल दूसरे सदस्य के लिए आगे बढ़ता है और इस "सामान्य" सदस्य को प्रति-उदाहरण __call__ कार्यान्वयन पर सेट करता है।

उत्तर

13

डबल-अंडरस्कोर विधियों को हमेशा कक्षा में देखा जाता है, कभी भी उदाहरण नहीं। Special method lookup for new-style classes देखें:

नई शैली कक्षाओं के लिए, विशेष तरीकों की अंतर्निहित आमंत्रण केवल सही ढंग से काम करने की गारंटी कर रहे हैं, एक वस्तु के प्रकार पर परिभाषित वस्तु का उदाहरण शब्दकोश में नहीं।

क्योंकि प्रकार एक ही आपरेशन का समर्थन करने की जरूरत है हो सकता है कि (इस स्थिति में विशेष विधि metatype पर देखा जाता है)।

उदाहरण के लिए, वर्गों प्रतिदेय (कि कैसे आप एक उदाहरण का उत्पादन है) कर रहे हैं, लेकिन अगर अजगर वास्तविक वस्तु पर __call__ विधि ऊपर देखा, तो तुम वर्गों है कि उनके उदाहरण के लिए __call__ लागू पर ऐसा कभी नहीं हो सकता। ClassObject()ClassObject.__call__() बन जाएगा जो विफल हो जाएगा क्योंकि self पैरामीटर अनबाउंड विधि में नहीं भेजा गया है। तो इसके बजाय type(ClassObject).__call__(ClassObject) का उपयोग किया जाता है, और instance() पर कॉल करने से type(instance).__call__(instance) पर अनुवाद किया जाता है।

+0

परिभाषित करने के लिए एक प्रति उदाहरण '__call__' कार्यान्वयन मैं वर्तमान में उपयोग कर रहा हूँ -लेवल '__call__' कि एक नियमित सदस्य के लिए आगे। हालांकि एक बदसूरत समाधान लगता है ... – 6502

+0

@ 6502: यह अनुशंसित काम है। यदि आपको वास्तव में एक प्रति-उदाहरण कॉल करने योग्य को प्रतिनिधि करने की आवश्यकता है, तो कक्षा-स्तर '__call__' में स्पष्ट रूप से ऐसा करने का ऐसा करने का सबसे अच्छा तरीका है। –

+0

@MartijnPieters प्रॉक्सी के अंदर एक पूर्णांक ऑब्जेक्ट स्टोर में सभी ऑपरेटरों ('__add__',' __rtruediv__', आदि) को आगे बढ़ाने के लिए एक काम क्या होगा? यदि संभव हो तो मैं मैन्युअल रूप से सभी विधियों को लागू नहीं करना चाहता हूं। – danijar

3
नई शैली कक्षाओं (डिफ़ॉल्ट 3.x) और 2.x में वस्तु से विरासत में मिली विशेषता अवरोधन तरीकों __getattr__ और __getattribute__ are no longer called for built-in operations उदाहरणों में से दुंदर अतिभारित तरीकों पर और इसके बजाय खोज वर्ग में शुरू होता है में

इसके पीछे तर्क, मेटा क्लास की उपस्थिति से पेश की गई तकनीकीता शामिल है।

क्योंकि वर्ग मेटाक्लास के उदाहरण हैं और चूंकि मेटाक्लास, कक्षाओं पर कार्य करने वाले कुछ संचालन को परिभाषित कर सकता है, कक्षा को छोड़कर (जिसे इस मामले में instance माना जा सकता है) समझ में आता है; आपको मेटाक्लास में परिभाषित विधि का आह्वान करने की आवश्यकता है जिसे कक्षाओं को संसाधित करने के लिए परिभाषित किया गया है (cls पहले तर्क के रूप में)। यदि इंस्टेंस लुक-अप का उपयोग किया गया था, तो लुक-अप क्लास विधि का उपयोग करेगा जिसे उस वर्ग के उदाहरणों के लिए परिभाषित किया गया है (self)।

एक और (विवादित कारण) शामिल है अनुकूलन: चूंकि उदाहरणों पर निर्मित आपरेशन आमतौर पर बहुत अक्सर लागू कर रहे हैं, लंघन उदाहरण देखने-अप पूरी तरह और वर्ग तक जाया जा सकता हमें कुछ समय बचाता है।[स्रोत लुट्ज़, सीखना अजगर, 5 वें संस्करण]


मुख्य क्षेत्र जहां इस जाता है जब प्रॉक्सी वस्तुओं है कि इरादे कॉल अग्रेषित करने के साथ __getattr__ और __getattribute__ ओवरलोड एम्बेडेड आंतरिक बनाने असुविधा का हो सकता है वस्तु। चूंकि अंतर्निहित आमंत्रण पूरी तरह से उदाहरण को छोड़ देगा, इसलिए वे पकड़े नहीं जाएंगे और प्रभाव के रूप में एम्बेडेड ऑब्जेक्ट को अग्रेषित नहीं किया जाएगा।

इसके लिए एक आसान, लेकिन थकाऊ, काम-आसपास वास्तव में उन सभी डंडर्स को अधिभारित करना है जिन्हें आप प्रॉक्सी ऑब्जेक्ट में अवरुद्ध करना चाहते हैं। फिर इन ओवरलोडेड डंडर्स में आप आवश्यकतानुसार आंतरिक ऑब्जेक्ट को कॉल का प्रतिनिधि बना सकते हैं।


सबसे आसान काम के आसपास मैं setattr साथ वर्ग Foo पर विशेषता सेट कर रहा है के बारे में सोच सकते हैं: एक वर्ग

setattr(Foo, '__call__', lambda *args: print(args)) 

f(1, 2, 3) 
(<__main__.Foo object at 0x7f40640faa90>, 1, 2, 3) 
+0

आप यहां मामलों को भ्रमित कर रहे हैं। पाइथन कुछ मामलों में अनुकूलन के रूप में '__getattribute__' को छोड़ देता है। लेकिन कक्षा पर विशेष तरीकों की तलाश करना अनुकूलन विकल्प नहीं है; टाइप * पर अभिनय विशेष तरीकों का सही ढंग से समर्थन करने के लिए इसकी आवश्यकता है। 'हैश (1) 'के साथ' हैश (int) 'की तुलना करें, उदाहरण के लिए, दोनों को समर्थित होने की आवश्यकता है। –

+0

मैंने कहा कि एक दूसरे कारण के रूप में; लेकिन क्या यह * ऑप्टिमाइज़ेशन के लिए भी विचार नहीं किया जा सकता है क्योंकि हमारे पास ** किसी दिए गए वर्ग के ** ** ** उदाहरण हैं, हम नए मॉडल में '__dict__' लुक-अप छोड़ते हैं? –

+0

वह लुकअप सस्ता है, और एक उदाहरण पर एक विशेष विधि को कॉल करते समय, * केवल एक उदाहरण * है। –

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