2013-08-29 20 views
28

Desidero chiedere che cosa significhi la chiamata with_metaclass() nella definizione di una classe.Metaclass Python: Comprensione di 'with_metaclass()'

Es .:

class Foo(with_metaclass(Cls1, Cls2)): 
  • Si tratta di un caso particolare in cui una classe eredita da una metaclasse?
  • La nuova classe è anche un metaclasse?

risposta

52

with_metaclass() è una funzione di classe di utilità fabbrica fornita dal six library per rendere più semplice lo sviluppo di codice sia per Python 2 e 3.

Si crea una classe base con la classe meta specificato per voi, compatibile con la versione di Python su cui stai eseguendo il codice.

Citando dalla documentazione:

creare una nuova classe con base classe base e metaclasse metaclasse. Questo è stato progettato per essere utilizzato in dichiarazioni di classe come questo:

from six import with_metaclass 

class Meta(type): 
    pass 

class Base(object): 
    pass 

class MyClass(with_metaclass(Meta, Base)): 
    pass 

Ciò è necessario perché la sintassi per collegare una metaclasse cambiato tra Python 2 e 3:

Python 2:

class MyClass(object): 
    __metaclass__ = Meta 

Python 3:

class MyClass(metaclass=Meta): 
    pass 

Il La funzione with_metaclass() si avvale del fatto che le metaclassi sono a) ereditate dalle sottoclassi e b) una metaclasse può essere utilizzata per generare nuove classi; si crea effettivamente una nuova classe di base utilizzando la metaclasse come una fabbrica di generare una classe vuota:

def with_metaclass(meta, *bases): 
    """Create a base class with a metaclass.""" 
    return meta("NewBase", bases, {}) 

metaclasse La classe NewBase base è meta, sia su Python 2 e 3.

+2

Giusto per chiarire, in sei, la sintassi (per abbinare il comportamento di python 2 e 3 sopra): 'classe MyClass (with_metaclass (Meta, object)): pass' (dove l'oggetto è facoltativo). –

12

UPDATE: la funzione six.with_metaclass() è stata successivamente modificata con una variante decoratore, ovvero @six.add_metaclass(). Questo aggiornamento corregge alcuni problemi di mro relativi agli oggetti di base. Il nuovo decoratore verrebbe applicato come segue:

import six 

@six.add_metaclass(Meta) 
class MyClass(Base): 
    pass 

Here are the patch notes e here is a similar, detailed example and explanation per utilizzare un decoratore alternativa.

Problemi correlati