2013-08-29 5 views
28

Ich möchte fragen, was der with_metaclass() Aufruf in der Definition einer Klasse bedeutet.Python Metaklasse: Verständnis der 'mit_metaclass()'

Z. B .:

class Foo(with_metaclass(Cls1, Cls2)): 
  • Ist es ein besonderer Fall, in dem eine Klasse von einem metaclass erbt?
  • Ist die neue Klasse auch eine Metaklasse?

Antwort

52

with_metaclass() ist eine Utility-Klasse Factory-Funktion durch die six library zur Verfügung gestellt, um es einfacher Code zu entwickeln, sowohl für Python 2 und 3.

Es schafft eine Basisklasse mit der angegebenen Meta-Klasse für Sie, kompatibel mit die Version von Python, auf der Sie den Code ausführen.

Zitiert aus der Dokumentation:

Erstellen Sie eine neue Klasse mit der Basisklasse Basis und metaclass metaclass. Dies soll in Klassendeklarationen wie folgt verwendet werden:

from six import with_metaclass 

class Meta(type): 
    pass 

class Base(object): 
    pass 

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

Dies ist erforderlich, da die Syntax eine Metaklasse geändert zwischen Python zu befestigen 2 und 3:

Python 2:

class MyClass(object): 
    __metaclass__ = Meta 

Python 3:

class MyClass(metaclass=Meta): 
    pass 

Die with_metaclass() Funktion nutzt die Tatsache, dass Metaklassen sind a) von Unterklassen geerbt, und b) eine Metaklasse kann verwendet werden, um neue Klassen zu generieren; es schafft effektiv eine neue Basisklasse durch die Metaklasse als eine Fabrik mit einer leeren Klasse zu generieren:

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

Die NewBase Basisklasse Metaklasse ist meta, sowohl auf Python 2 und 3.

+2

Nur um in sechs, die Syntax zu verdeutlichen (um das Verhalten von Python 2 und 3 oben zu entsprechen): 'Klasse MyClass (with_metaclass (Meta, Objekt)): pass' (wo das Objekt optional ist). –

12

UPDATE: Die six.with_metaclass()-Funktion wurde seither mit einer Decorator-Variante gepatcht, dh @six.add_metaclass(). Dieses Update behebt einige Probleme mit den Basisobjekten. Der neue Dekorateur würde wie folgt angewandt werden:

import six 

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

Here are the patch notes und here is a similar, detailed example and explanation für eine Dekorateur Alternative verwenden.