可调用类的查找规则:A()与A.\u call\u()

2024-06-06 21:05:45 发布

您现在位置:Python中文网/ 问答频道 /正文

为了更好地理解元类,我一直在通读this excellent post,遇到了一些让我困惑的行为。你知道吗

设置

class AMeta(type):
    # Disclaimer:  this is not what a real-world metaclass __call__ should look like!
    def __call__(self, *args):
        print("AMeta.__call__, self = {}, args = {}".format(self, args))

class A(metaclass=AMeta):
    def __call__(self, *args):
        print("A.__call__, self = {}, args = {}".format(self, args))

问题1

A.__call__(1, 2)打印A.__call__, self = 1, args = (2,)。你知道吗

参数直接转发(1出现在self的位置) 因此,似乎没有触发任何描述器。基于these lookup rules这可能是因为AMeta.__call__是一个非数据描述符(因此不是) 优先于A.__call__),也可能是因为__call__是一种神奇的方法,因此解释器会给它一些特殊的直接查找。你知道吗

我不确定这两个假设中哪一个是正确的,如果有的话。 如果有人知道答案,我将不胜感激!你知道吗

问题2A(1, 2)打印AMeta.__call__, self = <class '__main__.A'>, args = (1, 2)。你知道吗

元类的__call__被调用,这与AMeta__call__portrayal here在创建A实例时作为傀儡主控符是一致的。你知道吗

为什么元类的__call__在这里被调用?当我调用A(1, 2)构造函数样式时,什么查找规则在起作用?显然A(1, 2)不仅仅是A.__call__(1, 2)的语法糖。你知道吗

我见过很多其他的问题围绕着这些问题跳舞,但没有一个能直接回答它们。你知道吗

我正在使用/关注python3.7+。你知道吗


Tags: selfformatisdeftypeargscallthis
1条回答
网友
1楼 · 发布于 2024-06-06 21:05:45

问题1:

尽管__call__确实是一个由解释器专门处理的神奇方法,但是只有在说A()并隐式委托给__call__方法时,才会触发这种特殊行为。说A.__call__的执行方式与a.foo完全相同,这意味着,正如您所说,AMeta.__call__是一个非数据描述符,因此被A.__call__的显式定义覆盖

问题2:

与问题1不同,解释器对魔术方法的特殊处理在这里被调用。但是,包含元类会使事情变得有点复杂。测试用例大致相当于以下没有元类的代码:

class A:
    def __init__(self):
        self.__call__ = self.call2
    def call2(self, *args):
        print("call2, self = {}, args = {}".format(self, args))
    def __call__(self, *args):
        print("__call__, self = {}, args = {}".format(self, args))

我上面提到的魔术方法的特殊处理是,当试图使用A(1, 2)这样的语法隐式调用魔术方法时,Python会忽略直接在对象上设置的任何属性,而只关心在类型上设置的属性。你知道吗

因此,A(1, 2)type(A).__call__(A, 1, 2)的糖分(除了忽略类型上的任何__getattr____getattribute__方法的事实)。这就解释了为什么要调用元类上的__call__方法。你知道吗

相关问题 更多 >