__call__() python 元类中的方法

问题描述 投票:0回答:1

我有以下代码。

class CustomMetaClass(type):
    def __call__(self, *args, **kwargs):
        print("Custom call method is invoked from custom meta class.")

class Sample(metaclass=CustomMetaClass):
    def method(self):
        print("Printing from a method")

我有一个自定义元类和一个普通类(样本)。 “示例”与我的自定义元类相关联。

由于在 Python 中每件事都是一个对象,每当解释器遇到类定义时,就会为用户定义的类创建一个“类型”的实例。 这是通过调用元类的

__call__()
来完成的。

在上面的例子中,Sample 类与我的自定义元类相关联,因此打印语句应该已经执行;但实际上并没有运行。

但是当我创建 Sample (

Sample()
) 实例时,打印方法被调用。据我所知(来自不同的 stackoverflow 问题),相同的
__call__()
元类中的方法用于为用户类(在定义类时)以及用户定义类(即:
Sample()
)创建实例

有人可以帮忙我错在哪里吗?

python call metaclass
1个回答
2
投票

但是当我创建 Sample ( Sample() ) 实例时,打印方法 调用。据我所知(来自不同的 stackoverflow 问题), 元类中相同的 call() 方法用于创建 用户类的实例(在定义类时)以及 用户定义的类(即:Sample())

这是一个复杂的主题,结果证明你做错了。 类元类中的

__call__
是当您创建使用该元类定义的类的ordinary 实例时调用的。 (在这种情况下,当你执行
Sample()
).

创建类本身时在元类中执行的内容(

class Sample(...):
语句及其主体),元类中的方法
__new__
__init__
就是所谓的。

感知它完全与普通对象发生的事情相同:当您实例化一个类时,用

Sample()
,“Sample”类(即元类)上的
__call__
方法是被调用,它的作用是调用
__new__
,然后调用类本身的
__init__
方法-(在
class Sample(...):
的主体中定义的方法。

所以,发生的是,当执行“类”语句时 - 当它的主体被处理时,调用

metaclass
__call__ metaclass - 通常这是
type.__call__
可能是最奇怪的部分:
type
是它自己的元类。这是硬编码在 cPython 的源代码中。而这个
type.__call__
的执行会调用metaclass
 
init
and
new
. The 
call` on the "first stage" metaclass仅在创建类实例时执行。



In [7]: class Meta1(type):
   ...:     def __call__(mcls, *args):  # called when a class is created
   ...:         print("at __call__ of Meta1")
   ...:         return super().__call__(*args)
   ...: 

In [8]: class Meta2(type, metaclass=Meta1):
   ...:     def __new__(mcls, *args):
   ...:         print("at __new__ on Meta2")
   ...:         return super().__new__(mcls, *args)
   ...:     def __call__(cls, *args, **kw):  # called when an instance is created
   ...:         print ("at __call__ on Meta2")
   ...:         return super().__call__(*args, **kw)
   ...: 

In [9]: class Sample(metaclass=Meta2):
   ...:     def __init__(self):
   ...:         print("at __init__ on Sample")
   ...: 
at __call__ of Meta1
at __new__ on Meta2

In [10]: s = Sample()
at __call__ on Meta2
at __init__ on Sample


© www.soinside.com 2019 - 2024. All rights reserved.