2017-08-06 2 views
3

De ma compréhension de la méthode __call__ dans une classe implémente l'opérateur d'appel de fonction, par exemple:Comprendre __call__ avec métaclasses

class Foo: 
    def __init__(self): 
     print("I'm inside the __init__ method") 

    def __call__(self): 
     print("I'm inside the __call__ method") 

x = Foo() #outputs "I'm inside the __init__ method" 
x() #outputs "I'm inside the __call__ method" 

Cependant, je vais par la Python Cookbook et l'écrivain défini un métaclasse pour contrôler par exemple création de sorte que vous ne pouvez pas instancier un objet directement. Voici comment il l'a fait:

class NoInstance(type): 
    def __call__(self, *args, **kwargs): 
     raise TypeError("Can't instantaite class directly") 


class Spam(metaclass=NoInstance): 
    @staticmethod 
    def grok(x): 
     print("Spam.grok") 

Spam.grok(42) #outputs "Spam.grok" 

s = Spam() #outputs TypeError: Can't instantaite class directly 

Cependant, ce que je ne comprends pas comment s() n'a pas été appelé, mais il est la méthode __call__ a été appelé. Comment cela marche-t-il?

Répondre

2

Les métaclasses implémentent le comportement de la classe (pas l'instance). Alors, quand vous regardez la création d'instances:

x = Foo() 

Cette littéralement « appelle » la classe Foo. C'est pourquoi __call__ de la métaclasse est appelée avant que les méthodes __new__ et __init__ de votre classe initialisent l'instance.


Comme @Take_Care_ a souligné dans les commentaires d'un grand métaclasses est sur ressource ionelmc's blog post à propos de « Comprendre Python métaclasses ». Une image dans ce blog est directement applicable à votre situation:

enter image description here

L'image est directement copié du poste de blog.

+1

grande et simple réponse! . Si OP veut quelque chose de plus: https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/ –

+1

Merci. Ceci est exactement ce que je cherchais ! – electro7912

1

Une classe est simplement une instance de sa métaclasse. Puisque la métaclasse définit __call__(), appeler l'instance de la métaclasse, c'est-à-dire la classe, en tant que fonction, c'est-à-dire en tant que constructeur, l'invoquera.