元类和 when/how 函数被调用
Metaclasses and when/how functions are called
我正在尝试了解 metaclasses 在 python 中的工作原理 3. 我想知道的是:调用了哪些函数、调用顺序以及它们的签名和 returns.
例如,我知道 __prepare__
被调用时 class 与元 class 实例化参数 metaclass, name_of_subclass, bases
和 returns 一个字典表示实例化对象的未来命名空间。
我觉得我很理解__prepare__
在这个过程中的步骤。不过,我不知道的是 __init__
、__new__
和 __call__
。他们的论点是什么?他们return做什么?他们如何互相称呼,或者一般来说这个过程是如何进行的?目前,我一直在理解何时调用 __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__
实际上是一个静态方法,return 是某个对象的实例(通常是定义 __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
如果能帮助理解元classes,我们将不胜感激。我已经阅读了很多教程,但是我错过了其中的一些细节。
在元类的 __call__
方法中,您只调用了 Thing
的 __new__
,而不是 __init__
。似乎 __call__
的默认行为是同时调用它们,正如我们调用元类的继承 __call__
:
时所见
def __call__(subclass):
print('In meta __call__')
print('Creating {}.'.format(subclass))
return super().__call__(subclass)
这会打印:
Creating <class '__main__.Thing'>.
In sub __new__
In sub __init__
首先:__prepare__
是可选的,如果您所做的只是 return 默认 {}
空字典,则无需提供实现。
Metaclasses 的工作方式与 classes 完全相同,因为当您调用它们时,它们会生成一个对象。 classes 和 metaclasses 都是 factories。区别在于 metaclass 在调用时生成一个 class 对象,而 class 在调用时生成一个实例。
classes 和 metaclasses 都定义了一个默认的 __call__
实现,它基本上是:
- 调用
self.__new__
生成一个新对象。
- 如果新对象是 self / a class 的实例
元class,然后也对该对象调用
__init__
。
您生成了自己的 __call__
实现,它没有实现第二步,这就是 Thing.__init__
从未被调用的原因。
您可能会问:但是 __call__
方法是在 metaclass 上定义的。这是正确的,所以当您用 Thing()
调用 class 时, 正是调用的那个方法 。所有特殊方法(以 __
开头和结尾)都是 called on the type(例如 type(instance)
是 class,而 type(class)
是元 class)正是因为 Python 具有来自 classes 和 metaclasses 的实例的多级层次结构; class 本身的 __call__
方法用于使实例可调用。对于 metaclass()
调用,是 type
对象本身提供了 __call__
实现。没错,metaclasses 既是 subclasses 又是 type
的实例。
编写元class 时,如果您想自定义调用class 时发生的情况,则应仅实现__call__
。否则保留默认实现。
如果我从你的 metaclass 中删除 __call__
方法(并忽略 __prepare__
方法),那么 Thing.__init__
将再次被调用:
>>> class Logged(type):
... 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')
...
In meta __new__
In meta __init__
>>> thing = Thing()
In sub __new__
In sub __init__
我正在尝试了解 metaclasses 在 python 中的工作原理 3. 我想知道的是:调用了哪些函数、调用顺序以及它们的签名和 returns.
例如,我知道 __prepare__
被调用时 class 与元 class 实例化参数 metaclass, name_of_subclass, bases
和 returns 一个字典表示实例化对象的未来命名空间。
我觉得我很理解__prepare__
在这个过程中的步骤。不过,我不知道的是 __init__
、__new__
和 __call__
。他们的论点是什么?他们return做什么?他们如何互相称呼,或者一般来说这个过程是如何进行的?目前,我一直在理解何时调用 __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__
实际上是一个静态方法,return 是某个对象的实例(通常是定义 __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
如果能帮助理解元classes,我们将不胜感激。我已经阅读了很多教程,但是我错过了其中的一些细节。
在元类的 __call__
方法中,您只调用了 Thing
的 __new__
,而不是 __init__
。似乎 __call__
的默认行为是同时调用它们,正如我们调用元类的继承 __call__
:
def __call__(subclass):
print('In meta __call__')
print('Creating {}.'.format(subclass))
return super().__call__(subclass)
这会打印:
Creating <class '__main__.Thing'>.
In sub __new__
In sub __init__
首先:__prepare__
是可选的,如果您所做的只是 return 默认 {}
空字典,则无需提供实现。
Metaclasses 的工作方式与 classes 完全相同,因为当您调用它们时,它们会生成一个对象。 classes 和 metaclasses 都是 factories。区别在于 metaclass 在调用时生成一个 class 对象,而 class 在调用时生成一个实例。
classes 和 metaclasses 都定义了一个默认的 __call__
实现,它基本上是:
- 调用
self.__new__
生成一个新对象。 - 如果新对象是 self / a class 的实例
元class,然后也对该对象调用
__init__
。
您生成了自己的 __call__
实现,它没有实现第二步,这就是 Thing.__init__
从未被调用的原因。
您可能会问:但是 __call__
方法是在 metaclass 上定义的。这是正确的,所以当您用 Thing()
调用 class 时, 正是调用的那个方法 。所有特殊方法(以 __
开头和结尾)都是 called on the type(例如 type(instance)
是 class,而 type(class)
是元 class)正是因为 Python 具有来自 classes 和 metaclasses 的实例的多级层次结构; class 本身的 __call__
方法用于使实例可调用。对于 metaclass()
调用,是 type
对象本身提供了 __call__
实现。没错,metaclasses 既是 subclasses 又是 type
的实例。
编写元class 时,如果您想自定义调用class 时发生的情况,则应仅实现__call__
。否则保留默认实现。
如果我从你的 metaclass 中删除 __call__
方法(并忽略 __prepare__
方法),那么 Thing.__init__
将再次被调用:
>>> class Logged(type):
... 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')
...
In meta __new__
In meta __init__
>>> thing = Thing()
In sub __new__
In sub __init__