【发布时间】:2018-11-10 17:31:03
【问题描述】:
我正在尝试学习元类在 python 3 中的工作方式。我想知道的是:调用了哪些函数,以什么顺序调用,以及它们的签名和返回。
例如,我知道 __prepare__ 在使用参数 metaclass, name_of_subclass, bases 实例化具有元类的类时被调用,并返回表示实例化对象的未来命名空间的字典。
我觉得我很了解__prepare__ 在此过程中的步骤。不过,我不知道的是__init__、__new__ 和__call__。他们的论据是什么?他们返回什么?他们都是如何互相称呼的,或者一般来说这个过程是如何进行的?目前,当__init__ 被调用时,我一直无法理解。
这是我一直在搞乱的一些代码来回答我的问题:
#!/usr/bin/env python3
class Logged(type):
@classmethod
def __prepare__(cls, name, bases):
print('In meta __prepare__')
return {}
def __call__(subclass):
print('In meta __call__')
print('Creating {}.'.format(subclass))
return subclass.__new__(subclass)
def __new__(subclass, name, superclasses, attributes, **keyword_arguments):
print('In meta __new__')
return type.__new__(subclass, name, superclasses, attributes)
def __init__(subclass, name, superclasses, attributes, **keyword_arguments):
print('In meta __init__')
class Thing(metaclass = Logged):
def __new__(this, *arguments, **keyword_arguments):
print('In sub __new__')
return super(Thing, this).__new__(this)
def __init__(self, *arguments, **keyword_arguments):
print('In sub __init__')
def hello(self):
print('hello')
def main():
thing = Thing()
thing.hello()
if __name__ == '__main__':
main()
从这个和一些谷歌搜索,我知道__new__实际上是一个静态方法,它返回某个对象的实例(通常是定义__new__的对象,但并非总是如此),并且调用__init__制作时的一个实例。按照这种逻辑,我对为什么不调用 Thing.__init__() 感到困惑。有人可以照亮吗?
这段代码的输出打印了“hello”,因此正在创建一个 Thing 实例,这进一步让我对 init 感到困惑。这是输出:
In meta __prepare__
In meta __new__
In meta __init__
In meta __call__
Creating <class '__main__.Thing'>
In sub __new__
hello
任何理解元类的帮助将不胜感激。我已经阅读了很多教程,但我错过了其中的一些细节。
【问题讨论】:
-
__new__不是静态方法;这是一个特殊情况的 class 方法,因此您不必用@classmethod装饰它。 -
我想我不明白细微差别,但我相信你是对的@chepner。这就是我想要达到的,或多或少。
-
类方法接收调用类作为它的第一个参数;静态方法没有。
标签: python python-3.x metaprogramming metaclass