2015-09-30 9 views
8

जब भी आप ऑब्जेक्ट को कॉल करने का प्रयास करते हैं तो पाइथन की जादू विधि __call__ कहा जाता है। Cls()() इस प्रकार Cls.__call__(Cls()) के बराबर है।__call__ वास्तव में कैसे काम करता है?

फ़ंक्शन पाइथन में प्रथम श्रेणी की वस्तुएं हैं, जिसका अर्थ है कि वे केवल कॉल करने योग्य ऑब्जेक्ट्स हैं (__call__ का उपयोग करके)। हालांकि, __call__ स्वयं एक फ़ंक्शन है, इस प्रकार इसमें __call__ भी है, जिसका फिर से अपना __call__ है, जिसका फिर से अपना __call__ है।

तो Cls.__call__(Cls()) इस प्रकार Cls.__call__.__call__(Cls()) के बराबर है और फिर Cls.__call__.__call__.__call__(Cls()) और इतने आगे के बराबर है।

यह अनंत लूप कैसे समाप्त होता है? __call__ वास्तव में कोड निष्पादित करता है?

उत्तर

9

हुड के अंतर्गत, एक ही तंत्र, और लगभग सभी सीपीथन कार्यान्वयन में एक ही सी समारोह में आते हैं।एक वस्तु एक __call__ विधि, एक समारोह (जो खुद एक वस्तु), या अंतर्निहित वस्तु के साथ एक वर्ग का एक उदाहरण है या नहीं, सभी कॉल (अनुकूलित विशेष मामलों को छोड़कर) समारोह PyObject_Call पर पहुंचें। यही कारण है कि सी समारोह प्रकार (एक और PyObject struct) से वस्तु की PyObject struct के ob_type क्षेत्र से वस्तु के प्रकार हो जाता है, और फिर tp_call क्षेत्र है, जो एक समारोह सूचक है हो जाता है। यदि tp_call नहीं NULL है, यह के माध्यम से कॉल, आर्ग और kwargs संरचनाओं कि भी PyObject_Call को पारित किए गए साथ।

जब कोई वर्ग __call__ विधि को परिभाषित करता है, जो tp_call फ़ील्ड को उचित रूप से सेट करता है।

यहाँ एक लेख में विस्तार से यह सब समझा दिया गया है: Python internals: How callables work। यह पूरे PyObject_Call फ़ंक्शन को भी सूचीबद्ध और समझाता है, जो बहुत बड़ा नहीं है। यदि आप उस कार्य को अपने मूल आवास में देखना चाहते हैं, तो यह सीपीथॉन रेपो में Objects/abstract.c में है।

यह स्टैक ओवरफ्लो क्यू & ए: What is a "callable" in Python? भी प्रासंगिक है।

+0

आह धन्यवाद! यह सब अब समझ में आता है: डी –

1

वास्तविक अनंत लूप नहीं है, क्योंकि __call__ विधि उन सभी स्थितियों के लिए वास्तव में नहीं बुलाया जाता है ("कहा जाता है")। यह केवल तब ही लागू होता है जब किसी ऑब्जेक्ट पर फ़ंक्शन-जैसी कॉल होती है जो __call__ विधि प्रदान करती है।

सामान्य वर्ग तत्काल Cls(...) और नियमित कार्यात्मक आमंत्रण f() ज्ञात मामले हैं जिन्हें सीधे संभाला जाता है। आम तौर पर __call__() का एक वास्तविक मंगलाचरण नहीं है, इसलिए __call__ विधि आमंत्रण कि कभी भी हो सकता है, यहां तक ​​कि गहरी विरासत, metaclasses, आदि के साथ जटिल मामलों में एक परिमित संख्या में देखते हैं

क्योंकि वहाँ के रूप में कुछ विवाद था कि क्या वैचारिक अनंत लूप की शॉर्ट-सर्किटिंग वास्तव में हो रही थी, चलो अलग-अलग बाइटकोड देखें। निम्नलिखित कोड पर विचार करें:

def f(x): 
    return x + 1 

class Adder(object): 
    def something(self, x): 
     return x + 19 
    def __call__(self, x): 
     return x + 1 

def lotsacalls(y): 
    u = f(1) 
    a = Adder() 
    z = u + a.something(y) 
    return a(z * 10) 

क्षमा करें यह एक छोटे जटिल है, के रूप में मैं शॉर्ट सर्किट के कई उदाहरण दिखाना चाहते हैं - अर्थात्, सामान्य def काम करता है, __init__ कॉल, सामान्य तरीके, और __call__ विशेष तरीकों। अब:

annotated disassembly

तो यहाँ समय की एक श्रेणी है जब, अगर अजगर वास्तव में थे, वास्तव में वैचारिक __call__ आमंत्रण के "पेड़ चलने", यह Function (और संभवतः Method कक्षाओं का संदर्भ, और आह्वान करने के लिए किसी की __call__ विधियों)। यह नहीं है यह सभी मामलों में सरल बाइटकोड CALL_FUNCTION का उपयोग करता है, वैचारिक पेड़-चलने को कम सर्किट करना। तार्किक रूप से आप कल्पना कर सकते हैं कि एक वर्ग Function है जिसमें __call__ विधि है जो किसी फ़ंक्शन (यानी Function कक्षा का एक उदाहरण) कहा जाता है। लेकिन यह वास्तव में उस तरह से काम नहीं करता है। कंपाइलर, बाइटकोड दुभाषिया, और सी-भाषा अंडरपिनिंग के अन्य हिस्सों वास्तव में मेटा-क्लास पेड़ चलते नहीं हैं। वे पागल की तरह शॉर्ट-सर्किट।

+1

लेकिन काम करता है खुद को सिर्फ "वस्तुओं है कि' __call__' तरीका प्रदान "कर रहे हैं,' खुद __call__' भी शामिल है। इस प्रकार '__call__' का आह्वान करने के लिए, आप इसे '__call__' कहते हैं जो फिर से' __call__' कहता है। रेखा कहां जाती है, और यह किस पर आधारित है? –

+1

नहीं, वे वास्तव में नहीं हैं। * संकल्पनात्मक रूप से * उन्हें "केवल ऑब्जेक्ट्स" के रूप में देखा जा सकता है जो __call__ विधि प्रदान करते हैं, लेकिन वास्तव में उन्हें सीधे संकलक और रनटाइम द्वारा समझा जाता है, और सीधे लागू किया जाता है। यह फिबोनाकी अनुक्रम की तरह है, कहते हैं। हां, एक पूरी तरह से पुनरावर्ती परिभाषा है, और संभव कार्यान्वयन है। लेकिन अधिकांश वास्तविक कार्यान्वयन पुनरावृत्त हैं। वे लॉजिकल रिकर्सन को शॉर्ट-सर्किट करते हैं, ताकि श्रमिक रूप से लंबी रिकर्सन चेन से गुजरना पड़े। –

+0

मैं यह नहीं कह रहा कि आप गलत हैं, क्योंकि मुझे यकीन नहीं है, लेकिन क्या आप इसे साबित कर सकते हैं? वे मेरे लिए सामान्य वस्तुओं की तरह लगते हैं, और स्रोत कोड के लिंक के साथ ब्रायनो का जवाब और सभी मेरे सिद्धांत का समर्थन करते हैं। मैं यह नहीं कह रहा हूं कि मैं सही हूं और आप गलत हैं, लेकिन मेरे लिए यह वर्तमान में ऐसा लगता है कि वे केवल ऑब्जेक्ट्स हैं और यह सी कार्यान्वयन है जो केवल एक बार '__call__' को कॉल करता है, अगर किसी को परिभाषित किया गया हो। –

0

मैं किसी भी प्रलेखन जाँच नहीं था, लेकिन मेरी परीक्षणों से यह __call__ हमेशा नहीं बुलाया जाता है लग रहे हैं: अजगर उपयोग में सभी कॉल्स

def func1(*args, **kargs): 
    print "func1 called", args, kargs 

def func2(*args, **kargs): 
    print "func2 called", args, kargs 

func1.__call__ = func2 

func1() # here is still called func1 

class Cls: 
    def __init__(*args, **kargs): 
     print "init called", args, kargs 
    def __call__(*args, **kargs): 
     print "object called", args, kargs 

obj = Cls() # here is actually called __init__ 
obj() # here is called __call__ 

इस प्रिंट

func1 called() {} 
init called (<__main__.Cls instance at 0x0000000002A5ED88>,) {} 
object called (<__main__.Cls instance at 0x0000000002A5ED88>,) {} 
+0

'obj = cls() 'नोटिस के साथ कि' Cls' केवल 'टाइप' का एक उदाहरण है, इसलिए यह' type .__ कॉल __() 'के बराबर होगा। (Google: मेटाक्लास)। हालांकि पहली खोज दिलचस्प है, किसी को भी पता है कि क्यों 'func1 .__ call__' का आह्वान नहीं किया जाता है? –

+0

@gre_gor खूबसूरती से अनुभवजन्य प्रदर्शन जो काम करता है विशेष-आधारित हैं! –

+0

@MarkusMeskanen हां। 'func1 .__ call__' को नहीं बुलाया गया है क्योंकि यह एक विशेष मामला है। पाइथन को "फ़ंक्शंस केवल ऑब्जेक्ट्स" की पूर्ण अवधारणा को पार करने की आवश्यकता नहीं है, क्योंकि यह एक बहुत ही आम, जाने-माने स्थिति है, शिकायतकर्ता/रनटाइम अधिक सीधे संभाल सकता है। पाइथन कार्यान्वयन में ऐसे शॉर्टकट के ** ** ** उदाहरण हैं। पायथन का उद्देश्य उच्च स्तरीय अर्थशास्त्र के लिए है, लेकिन यह अक्सर प्रदर्शन के लिए विशेष मामलों और सी कोड में कूद जाता है। –

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