Je veux demander ce que l'appel with_metaclass()
signifie dans la définition d'une classe.
Par exemple.:
class Foo(with_metaclass(Cls1, Cls2)):
with_metaclass()
est une fonction d'usine de classe utilitaire fournie par la bibliothèque six
pour faciliter le développement de code pour les deux Python 2 et 3.
Il utilise un peu de main (voir ci-dessous) avec une métaclasse temporaire, pour attacher une métaclasse à une classe régulière d'une manière qui est compatible avec les deux Python 2 et Python 3.
Citant de la documentation:
Créez une nouvelle classe avec la classe de base et la métaclasse de métaclasse. Ceci est conçu pour être utilisé dans des déclarations de classe comme ceci:
from six import with_metaclass class Meta(type): pass class Base(object): pass class MyClass(with_metaclass(Meta, Base)): pass
Cela est nécessaire car la syntaxe pour attacher une métaclasse a changé entre Python 2 et 3:
Python 2:
class MyClass(object):
__metaclass__ = Meta
Python 3:
class MyClass(metaclass=Meta):
pass
La fonction with_metaclass()
utilise le fait que les métaclasses sont a) héritées par des sous-classes, et b) une métaclasse peut être utilisée pour générer de nouvelles classes et c) lorsque vous sous-classe à partir d'une classe de base avec une métaclasse, créant l'objet de sous-classe réel est délégué à la métaclasse. Il crée efficacement une nouvelle classe de base temporaire avec une métaclasse metaclass
temporaire qui, lorsqu'elle est utilisée pour créer la sous-classe , remplace la base temporaire combo classe et métaclasse avec la métaclasse de votre choix:
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
@classmethod
def __prepare__(cls, name, this_bases):
return meta.__prepare__(name, bases)
return type.__new__(metaclass, 'temporary_class', (), {})
Décomposer ce qui précède:
type.__new__(metaclass, 'temporary_class', (), {})
utilise la métaclasse metaclass
pour créer un nouvel objet de classe nommé temporary_class
qui est entièrement vide sinon. type.__new__(metaclass, ...)
est utilisé à la place de metaclass(...)
pour éviter d'utiliser l'implémentation spéciale metaclass.__new__()
qui est nécessaire au fonctionnement de la main légère dans une prochaine étape.temporary_class
Est utilisé comme classe de base, Python appelle d'abord metaclass.__prepare__()
(en passant le nom de classe dérivé, (temporary_class,)
comme argument this_bases
. La métaclasse prévue meta
est alors utilisé pour appeler meta.__prepare__()
, ignorant this_bases
et passant l'argument bases
.metaclass.__prepare__()
comme espace de noms de base pour les attributs de classe (ou simplement en utilisant un dictionnaire simple lorsque on Python 2), Python appelle metaclass.__new__()
pour créer la classe réelle. Ceci est à nouveau passé (temporary_class,)
Comme tuple this_bases
, Mais le code ci-dessus l'ignore et utilise bases
à la place, en appelant meta(name, bases, d)
pour créer la nouvelle classe dérivée.Par conséquent, l'utilisation de with_metaclass()
vous donne un nouvel objet de classe sans classes de base supplémentaires :
>>> class FooMeta(type): pass
...
>>> with_metaclass(FooMeta) # returns a temporary_class object
<class '__main__.temporary_class'>
>>> type(with_metaclass(FooMeta)) # which has a custom metaclass
<class '__main__.metaclass'>
>>> class Foo(with_metaclass(FooMeta)): pass
...
>>> Foo.__mro__ # no extra base classes
(<class '__main__.Foo'>, <type 'object'>)
>>> type(Foo) # correct metaclass
<class '__main__.FooMeta'>
[~ # ~] mise à jour [~ # ~] : la fonction six.with_metaclass()
a depuis été corrigée avec une variante décoratrice, c'est-à-dire @six.add_metaclass()
. Cette mise à jour résout certains problèmes de macro liés aux objets de base. Le nouveau décorateur serait appliqué comme suit:
import six
@six.add_metaclass(Meta)
class MyClass(Base):
pass
Voici les notes de mise à jour et voici un exemple et une explication similaires et détaillés pour l'utilisation d'une alternative de décoration.