2011-09-20 5 views
5

dire che ho ottenuto un metaclasse:metaclasse di "__call__" e "__init__" del prodotto di classe

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) 

uscita come segue:

Meta: __call__ with (1,) 

Domanda:

Perché non è __init__ prodotto ProductClass attivato? Solo a causa di Meta __call__?

UPDATE:

Ora, aggiungo __new__ per 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) 

E 'responsabilità di Meta 's __call__ alla chiamata di __new__ e __init__ ProductClass?

risposta

4

Sì, è fino a Meta.__call__ chiamare ProductClass.__init__ (oppure no, a seconda del caso).

Per citare il documentation: comportamento personalizzato

ad esempio la definizione di un metodo personalizzato __call__() nel metaclasse permette quando la classe è chiamata, per esempio non sempre creazione di una nuova istanza.

Quella pagina cita anche uno scenario in cui il __call__ metaclasse può restituire un'istanza di una classe diversa (vale a dire non ProductClass nel tuo esempio). In questo scenario sarebbe chiaramente inappropriato chiamare automaticamente ProductClass.__init__.

+0

cosa succede se ho ottenuto un "__new__" in ProductClass? "__call__" di Meta chiamerà ProductClass "__new__" e "__init__"? Vedi il mio AGGIORNAMENTO. – Alcott

+0

E a quanto pare, "__call__" di Meta viene chiamato prima di "__new__" di ProductClass. – Alcott

+0

Il problema è che 'Meta .__ call__' è richiesto per chiamare' ProductClass .__ new__' e 'ProductClass .__ init__'. Normalmente, 'type .__ call__' fa questo per te, ma quando definisci' Meta .__ call__' tu _override_ quel comportamento, il che significa che non viene eseguito a meno che tu non lo faccia. Quindi, sei obbligato a chiamare "__new__" e "__init__" da solo, o effettuare una chiamata a qualcosa come "type .__ call __ (cls, * args)'. –

6

C'è una differenza di OOP tra estendere un metodo e l'override di esso, quello che hai appena fatto nel tuo metaclasse Meta si chiama imperativa perché si è definito il metodo di __call__ e non hai chiamato il genitore __call__. per avere il comportamento che si desidera si deve estendere __call__ metodo chiamando il metodo parent:

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