用元类理解 __call__

ele*_*912 7 python metaprogramming metaclass class

根据我的理解,__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"
Run Code Online (Sandbox Code Playgroud)

但是,我正在阅读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
Run Code Online (Sandbox Code Playgroud)

但是,我不明白的是如何s()不被调用,但它的__call__方法被调用了。这是如何运作的?

MSe*_*ert 7

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

x = Foo()
Run Code Online (Sandbox Code Playgroud)

这从字面上“调用”了 class Foo。这就是为什么__call__在类的__new____init__方法初始化实例之前调用元类的原因。


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

在此处输入图片说明

图片直接复制自博文。