web-dev-qa-db-fra.com

Quelles sont les différences entre une «méthode de classe» et une méthode de métaclasse?

En Python, je peux créer une méthode de classe en utilisant le décorateur @classmethod:

>>> class C:
...     @classmethod
...     def f(cls):
...             print(f'f called with cls={cls}')
...
>>> C.f()
f called with cls=<class '__main__.C'>

Alternativement, je peux utiliser une méthode normale (instance) sur une métaclasse:

>>> class M(type):
...     def f(cls):
...             print(f'f called with cls={cls}')
...
>>> class C(metaclass=M):
...     pass
...
>>> C.f()
f called with cls=<class '__main__.C'>

Comme le montre la sortie de C.f(), ces deux approches fournissent des fonctionnalités similaires.

Quelles sont les différences entre l'utilisation de @classmethod Et l'utilisation d'une méthode normale sur une métaclasse?

12
user200783

Dans votre exemple, la différence serait dans certaines autres classes qui auront M défini comme leur métaclasse.

class M(type):
    def f(cls):
        pass

class C(metaclass=M):
    pass

class C2(metaclass=M):
    pass

C.f()
C2.f()
class M(type):
     pass

class C(metaclass=M):
     @classmethod
     def f(cls):
        pass

class C2(metaclass=M):
    pass

C.f()
# C2 does not have 'f'

Voici plus sur les métaclasses Quels sont les cas d'utilisation (concrets) pour les métaclasses?

0
andole

@Classmethod et Metaclass sont différents.

Tout dans python est un objet. Chaque chose signifie chaque chose.

Qu'est-ce que la métaclasse?

Comme dit, chaque chose est un objet. Les classes sont également des objets, en fait, les classes sont des instances d'autres objets mystérieux formellement appelés méta-classes. La métaclasse par défaut dans python est "type" si non spécifié

Par défaut, toutes les classes définies sont des instances de type.

Les classes sont des instances de méta-classes

Peu de points importants sont de comprendre le comportement mentionné

  • Comme les classes sont des instances de méta-classes.
  • Comme tout objet instancié, les objets (instances) obtiennent leurs attributs de la classe. La classe obtiendra ses attributs de Meta-Class

Envisagez de suivre le code

class Meta(type):
    def foo(self):
        print(f'foo is called self={self}')
        print('{} is instance of {}: {}'.format(self, Meta, isinstance(self, Meta)))

class C(metaclass=Meta):
    pass

C.foo()

Où,

  • la classe C est une instance de la classe Meta
  • "classe C" est un objet de classe qui est une instance de "classe Meta"
  • Comme tout autre objet (instance), la "classe C" a accès à ses attributs/méthodes définis dans sa classe "classe Meta"
  • Donc, décodage de "C.foo ()". "C" est une instance de "Meta" et "foo" est une méthode d'appel via une instance de "Meta" qui est "C".
  • Le premier argument de la méthode "foo" fait référence à l'instance et non à la classe contrairement à "classmethod"

On peut vérifier que si "classe C" est une instance de "Class Meta

  isinstance(C, Meta)

Qu'est-ce que la méthode de classe?

Les méthodes Python seraient liées. Comme python impose la restriction, cette méthode doit être invoquée uniquement avec l'instance. Parfois, nous pouvons souhaiter invoquer des méthodes directement via la classe sans aucune instance (un peu comme les membres statiques en Java) sans avoir à créer d'instance. Par exemple, une instance par défaut est requise pour appeler la méthode. Comme solution de contournement, python fournit une méthode de classe de fonction intégrée pour lier une méthode donnée à une classe au lieu d'une instance.

Comme les méthodes de classe sont liées à la classe. Il prend au moins un argument qui fait référence à la classe elle-même au lieu de l'instance (self)

si la méthode de classe fonction/décorateur intégrée est utilisée. Le premier argument sera la référence à la classe au lieu de l'instance

class ClassMethodDemo:
    @classmethod
    def foo(cls):
        print(f'cls is ClassMethodDemo: {cls is ClassMethodDemo}')

Comme nous avons utilisé "classmethod", nous appelons la méthode "foo" sans créer d'instance comme suit

ClassMethodDemo.foo()

L'appel de méthode ci-dessus renverra True. Puisque le premier argument cls fait en effet référence à "ClassMethodDemo"

Résumé:

  • Classmethod reçoit le premier argument qui est "une référence à la classe (traditionnellement appelée cls) elle-même"
  • Les méthodes des méta-classes ne sont pas des méthodes de classe. Les méthodes des méta-classes reçoivent le premier argument qui est "une référence à l'instance (traditionnellement appelée self) et non à la classe"
0
neotam