2011-09-20 11 views
5

Dicen que tengo una metaclase:MetaClass de "__call__" y "__init__" del producto de clase

class Meta(type): 
    def __call__(cls, *args): 
     print "Meta: __call__ with", args 

class ProductClass(object): 
    __metaclass__ = Meta 
    def __init__(self, *args): 
     print "ProductClass: __init__ with", args 

p = ProductClass(1) 

de salida de la siguiente manera:

Meta: __call__ with (1,) 

Pregunta:

¿Por qué no es ¿Se activó __init__ de ProductClass? ¿Solo por el __call__ de Meta?

ACTUALIZACIÓN:

Ahora, agrego __new__ para ProductClass:

class ProductClass(object): 
     __metaclass__ = Meta 
     def __new__(cls, *args): 
      print "ProductClass: __new__ with", args 
      return super(ProductClass, cls).__new__(cls, *args) 
     def __init__(self, *args): 
      print "ProductClass: __init__ with", args 

p = ProductClass(1) 

Es responsabilidad __call__ 's de Meta a la llamada de __new__ y __init__ ProductClass?

Respuesta

4

Sí, es hasta Meta.__call__ para llamar al ProductClass.__init__ (o no, según sea el caso).

Para citar el documentation: comportamiento personalizado

por ejemplo definiendo un método personalizado __call__() en la metaclase permite cuando la clase se llama, por ejemplo, no siempre creando una nueva instancia.

Esa página también menciona un escenario en el que __call__ de la metaclase puede devolver una instancia de una clase diferente (es decir, no ProductClass en su ejemplo). En este escenario, sería claramente inapropiado llamar al ProductClass.__init__ automáticamente.

+0

lo que si me dieron una "__new__" en ProductClass? ¿El "__call__" de Will Meta llama a "__new__" y "__init__" de ProductClass? Ver mi ACTUALIZACIÓN. – Alcott

+0

Y aparentemente, se llama primero a "__call__" de Meta antes de "__new__" de ProductClass. – Alcott

+0

El problema es que 'Meta .__ call__' es necesario para llamar a' ProductClass .__ new__' y 'ProductClass .__ init__'. Normalmente, 'type .__ call__' hace esto por usted, pero cuando define' Meta .__ call__' usted _override_ ese comportamiento, lo que significa que no se ejecuta a menos que lo haga. Entonces, se requiere que usted llame '' __new__' y '__init__' usted mismo, o haga una llamada a algo como' escriba .__ call __ (cls, * args) '. –

6

Hay una diferencia en la programación orientada a objetos que se extiende entre un método y anulando él, lo que acabas de hacer en su metaclase Meta se llama determinante dado que se ha definido el método de __call__ y que no llame al padre __call__. para tener el comportamiento que desea que usted tiene que extender __call__ método mediante una llamada al método parent:

class Meta(type): 
    def __call__(cls, *args): 
     print "Meta: __call__ with", args 
     return super(Meta, cls).__call__(*args) 
Cuestiones relacionadas