2016-07-31 12 views
0
import inspect 
class meta(type): 
    def __new__(cls, t_name, bases, argdict): 
     print "inside meta __new__" 
     return super(meta, cls).__new__(cls, t_name, bases, argdict) 

    def __init__(self, t_name, bases, argdict): 
     print "inside __init__ of meta" 

    def __call__(cls, *args, **kwargs): 
     print "*************************" 
     print "inside __call__ of meta" 
     print cls, args, kwargs #--> cls is A 
     # How cls is passed as __call__ does not take cls param? through super/how? Why super requires cls? 
     inst = super(meta, cls).__call__(*args, **kwargs) # why no cls to call? how super works here 
     #inst = type.__call__(cls, *args, **kwargs) # this works well 
     print inst, "instance inside meta" 
     print "*************************" 
     return inst 


class A(object): 
    __metaclass__ = meta # this line triggers metaclass 

    def __new__(cls, *args, **kwargs): 
     print "inside A __new__" 
     print cls, args, kwargs # we get cls here as A 
     inst = super(A, cls).__new__(cls, *args, **kwargs) 
     print inst, "instance inside A" 
     return inst 

    def __init__(self, *args, **kwargs): 
     print "inside A __init___" 
     self.attr = args[0] 

    def __call__(self, *args, **kwargs): 
     print "inside A __call__ " 
     print self, args, kwargs 



a = A("simple arg") # this is type(A).__call__(A, ...) ==   meta.__call__(A, ...) 
print a 
a("param") # type(a).__call__(a), ... 
print type(A) 

OUTPUTКак работает метакласс (__call__)?

inside meta __new__ 
inside __init__ of meta 
************************* 
inside __call__ of meta 
<class '__main__.A'> ('simple arg',) {} 
inside A __new__ 
<class '__main__.A'> ('simple arg',) {} 
<__main__.A object at 0x7ff0010f2c10> instance inside A 
inside A __init___ 
<__main__.A object at 0x7ff0010f2c10> instance inside meta 
************************* 
<__main__.A object at 0x7ff0010f2c10> 
inside A __call__ 
<__main__.A object at 0x7ff0010f2c10> ('param',) {} 
<class '__main__.meta'> 
<type 'type'> 
True 

У меня есть несколько вопросов, внедренные в код [не прикладывая здесь, как это сделает вопрос более больше]

ответ

0

Первый аргумент метода является экземпляром. Экземпляр метакласса - это класс, поэтому мы называем аргумент cls.

super() нуждается в экземпляре, чтобы он мог правильно следить за MRO. Его методы уже привязаны к соответствующему экземпляру и поэтому не нужно явно передавать экземпляр.

+0

Спасибо ignacio, первая часть Я понял, почему мы называем это 'cls'. но вторая часть неясна, может быть, глупые вопросы 'type type() триггеров типа .__ call__' как и все остальные вызовы? ? и имеет ли '__new__' явное требование для cls, и почему мы его предоставляем? –

+0

Все вызовы связаны с методом '__call __()' напрямую или иным образом. '__new __()' [определяется таким образом] (https://docs.python.org/2/reference/datamodel.html#object.__new__). –