用元类理解__call__

时间:2017-08-06 21:01:06

标签: python class metaprogramming metaclass

根据我的理解,类中的__call__方法实现了函数调用操作符,例如:

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"

但是,我正在浏览Python Cookbook并且编写器定义了一个元类来控制实例创建,这样就无法直接实例化对象。他就是这样做的:

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

然而,我没有得到的是s()未被调用的方式,但调用了__call__方法。这是如何工作的?

2 个答案:

答案 0 :(得分:3)

元类实现类的行为(不是实例)。因此,当您查看实例创建时:

x = Foo()

这实际上是“调用”类Foo。这就是为什么在类的__call____new__方法初始化实例之前调用元类的__init__的原因。

正如@Take_Care_在评论中指出的,关于元类的一个很好的资源是ionelmc's blog post关于“理解Python元类”。该博客文章中的一张图片直接适用于您的情况:

enter image description here

图片直接从博文中复制。

答案 1 :(得分:1)

一个类只是其元类的一个实例。由于元类定义了__call__(),因此调用元类的实例(即类)作为函数,即作为构造函数,将调用它。