2015-06-15 10 views
11

कौन कॉल करता है यह वास्तव में SO पर चर्चा से उत्पन्न होता है।मेटाक्लास

लघु संस्करण जब Klass वर्ग घोषणा निष्पादित किया जाता है

def meta(name, bases, class_dict) 
    return type(name, bases, class_dict) 

class Klass(object): 
    __metaclass__ = meta 

meta() कहा जाता है।

(पायथन आंतरिक) कोड का कौन सा हिस्सा वास्तव में meta() पर कॉल करता है?

लांग संस्करण

जब वर्ग घोषित किया जाता है, कुछ कोड उचित विशेषता के चेक करते हैं और अगर वहाँ एक __metaclass__ एक प्रकार पर घोषित देखने के लिए है। यदि ऐसा मौजूद है, तो उसे उस मेटाक्लास पर अच्छी तरह से ज्ञात (class_name, bases, class_dict) विशेषताओं के साथ एक विधि कॉल करना होगा। यह वास्तव में मुझे स्पष्ट नहीं है कि उस कॉल के लिए कौन सा कोड ज़िम्मेदार है।

मैंने सीपीथॉन में कुछ खुदाई की है (नीचे देखें), लेकिन मैं वास्तव में एक निश्चित उत्तर के करीब कुछ लेना चाहता हूं।

विकल्प 1: कहा जाता है सीधे

metaclass कॉल वर्ग पार्स में hardwired है। यदि हां, तो क्या इसके लिए कोई सबूत है?

विकल्प 2: यह type_call() कॉल type_new() जो बारी में कॉल _PyType_CalculateMetaclass() में type.__new__()

कोड द्वारा कहा जाता है। यह पता चलता है कि metaclass संकल्प वास्तव में जब पता लगाने के लिए जो मूल्य धारणा के साथ लाइन में से type()

वापस जाने के लिए यह किया जाएगा कि एक "वर्ग" एक "प्रतिदेय है कि एक रिटर्न की कोशिश कर रहा type() को कॉल के दौरान किया जाता है ऑब्जेक्ट "।

विकल्प 3: कुछ अलग

मेरे सभी अनुमान शायद पूरी तरह से गलत ज़ाहिर है,।

कुछ उदाहरण मामलों है कि हम बातचीत में के साथ आया था:

उदाहरण 1:

class Meta(type): 
    pass 

class A: 
    __metaclass__ = Meta 

A.__class__ == Meta 

यह वही है Meta.__new__() रिटर्न है, इसलिए इस कानूनी लगता है।

class Meta(type): 
    def __new__(cls, class_name, bases, class_dict): 
     return type(class_name, bases, class_dict) 

class A(object): 
    __metaclass__ = Meta 

A.__class__ == type 

संपादित करें 2: सही शुरुआती संस्करण, ठीक से type से Meta निकाले जाते हैं metaclass रूप A.__class__

उदाहरण 2 ही डालता है।

ठीक लगता है, लेकिन मुझे सच में यकीन नहीं है कि यह ऐसा करता है जो मुझे लगता है। इसके अलावा: उदाहरण 1 में व्यवहार करने के लिए कैननिकल विधि क्या है?

संपादित करें 3: का उपयोग करना type.__new__(...) जो भी मुझे प्रबुद्ध अधिक गहराई से आंतरिक अजगर जादू की जानकारी रखने वाले विकल्प 2.

कर सकते हैं किसी को भी करने के पक्ष में लगता अपेक्षा के अनुरूप काम करने के लिए, लगता है?

संपादित करें: मेटाक्लास पर एक संक्षिप्त संक्षिप्त प्राइमर के लिए ए: http://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/। इसके अलावा कुछ वाकई अच्छे आरेख, संदर्भ भी हैं और पाइथन 2 और 3 के बीच अंतर को भी हाइलाइट करते हैं।

संपादित करें 3: पाइथन 3 के लिए नीचे एक अच्छा जवाब है। पायथन 3 कक्षा ऑब्जेक्ट बनाने के लिए __build_class__ का उपयोग करता है। कोड पथ है - कहीं भी - पायथन में अलग 2.

+1

http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python –

+1

एफडब्ल्यूआईडब्ल्यू, मूल चर्चा इस बारे में थी कि 'SomeClass()' कुछ क्लास .__ वर्ग __.__ कॉल __() को हल करता है या नहीं '(जो आखिरकार 'टाइप .__ नया __()', या यदि iit' टाइप 'करने का संकल्प करता है।__call __() '(जो 'SomeClass .__ वर्ग __.__ call__' के प्रतिनिधि होगा)। –

+0

@brunodesthuilliers मुझे लगता है कि हमने अभी हल किया है और यह पूर्व है। अभी भी कुछ पहेलियों को खुलता है, हालांकि :) – dhke

उत्तर

6

आप अपेक्षाकृत आसानी से जवाब पा सकते हैं:

अजगर 2 कोड कुछ ऐसा ही। सबसे पहले, कक्षा बनाने के लिए ओपोड ढूंढें।

>>> def f(): 
    class A(object): 
     __metaclass__ = type 

>>> import dis 
>>> dis.dis(f) 
    2   0 LOAD_CONST    1 ('A') 
       3 LOAD_GLOBAL    0 (object) 
       6 BUILD_TUPLE    1 
       9 LOAD_CONST    2 (<code object A at 0000000001EBDA30, file "<pyshell#3>", line 2>) 
      12 MAKE_FUNCTION   0 
      15 CALL_FUNCTION   0 
      18 BUILD_CLASS   
      19 STORE_FAST    0 (A) 
      22 LOAD_CONST    0 (None) 
      25 RETURN_VALUE  

तो ऑपोड BUILD_CLASS है। आइए अब उस शब्द के स्रोत को खोजें (आसानी से github mirror पर किया गया)।

आपको कुछ परिणाम मिलते हैं, लेकिन इनमें से सबसे दिलचस्प Python/ceval.c है जो static PyObject * build_class(PyObject *, PyObject *, PyObject *); फ़ंक्शन घोषित करता है और BUILD_CLASS के लिए केस स्टेटमेंट है।

result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, 
         NULL); 

तो जवाब है metaclass संकल्प लिया और कहा जाता है: फ़ाइल के माध्यम से खोज और आप build_class के समारोह परिभाषा लाइन 4430. में शुरू और लाइन 4456 पर हम कोड का सा लगता है पा सकते हैं आप देख रहे हैं BUILD_CLASS ऑपोड निष्पादित करने के लिए ज़िम्मेदार फ़ंक्शन द्वारा।

+0

एक पायथन 3 उदाहरण की तरह दिखता है - ओपी ने पूछा कि यह पाइथन 2.7.x –

+1

कोड में कैसे काम करता है https://github.com/python-git/python से है जो 2.7 के लिए है । 'Build_class' फ़ंक्शन को अधिक ध्यान से देखें, क्या आप इसे निश्चित रूप से देख सकते हैं 2.7 यह वास्तव में '__metaclass__' नाम की तलाश में है, जिसे 3.x में अनदेखा किया जाता है। – Dunes

+0

हाँ, यह पायथन 2 का उत्तर है। मैं लगभग एक ही बात कहने के लिए अपने उत्तर को अपडेट करने वाला था। मैं अभी भी अपना जवाब थोड़ा सा अपडेट कर दूंगा, लेकिन आपको मेरे द्वारा +1 भी मिल जाएगा! – Blckknght

-4

वर्ग परिभाषा निष्पादित होने पर मेटा वर्ग दुभाषिया द्वारा "तत्काल" होते हैं।

2

अजगर 3 में, metaclass __build_class__ builtin समारोह (जो class बयान को संभालने के लिए कहा जाता है) के लिए कोड में कहा जाता है। यह फ़ंक्शन पायथन 3 में नया है, और पाइथन 2 में समकक्ष सी फ़ंक्शन build_class को पाइथन स्तर पर सार्वजनिक रूप से उजागर नहीं किया गया है। आप फिर भी python/ceval.c

वैसे भी में स्रोत मिल सकता है, यहाँ में metaclass वस्तु के लिए प्रासंगिक कॉल है अजगर 3 __build_class__ कार्यान्वयन:

cls = PyEval_CallObjectWithKeywords(meta, margs, mkw); 

चर meta metaclass है (या तो type या किसी अन्य metaclass से पाया एक तर्क या बेस क्लास के प्रकार से)। margs स्थितित्मक तर्कों के साथ एक tuple है (name, bases, dct) और mkw मेटाक्लास (एक पायथन 3 केवल चीज़) के लिए कीवर्ड तर्क के साथ एक शब्दकोश है।

result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, 
             NULL); 
संबंधित मुद्दे