Ant*_*osa 1 python metaprogramming metaclass python-3.x
我正在尝试学习元类如何在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()
Run Code Online (Sandbox Code Playgroud)
从这个和一些谷歌搜索,我知道这__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
Run Code Online (Sandbox Code Playgroud)
任何帮助理解元类将不胜感激.我已经阅读了不少教程,但我错过了其中的一些细节.
首先:__prepare__
是可选的,如果您所做的只是返回默认的{}
空字典,则不需要提供实现.
元类的工作方式与类完全相同,因为当您调用它们时,它们会生成一个对象.类和元类都是工厂.不同之处在于,元类在调用时会生成一个类对象,一个类在调用时会生成一个实例.
类和元类都定义了一个默认__call__
实现,它基本上是这样做的:
self.__new__
生成一个新对象.__init__
该对象.您生成了自己的__call__
实现,但没有实现第二步,这Thing.__init__
就是从未调用过的原因.
您可能会问:但该__call__
方法是在元类上定义的.这是正确的,所以正是你用这个类调用时调用的方法Thing()
.所有特殊方法(开始和结束__
)都在类型上调用(例如type(instance)
是类,并且type(class)
是元类),因为Python具有来自元类的类的多级实例层次结构; 一__call__
类本身的方法是用来做实例调用.对于metaclass()
调用,它是type
提供__call__
实现的对象本身.没错,元类同时是子类和实例type
.
编写元类时,只有__call__
在要调整调用类时会发生的事情时才应该实现.保留默认实现.
如果我__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__
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
196 次 |
最近记录: |