[英]Metaclasses in Python: a couple of questions to clarify
在与元类崩溃之后,我深入研究了 Python 中的元编程主题,我有几个问题,恕我直言,在可用的文档中没有明确回答。
__new__
和__init__
时,它们的 arguments 必须定义相同吗?__init__
的最有效方法是什么?在元类中同时使用__new__
和__init__
时,它们的 arguments 必须定义相同吗?
我认为Alex Martelli解释得最简洁:
class Name(Base1,Base2): <<body>> __metaclass__==suitable_metaclass
方法
Name = suitable_metaclass('Name', (Base1,Base2), <<dict-built-by-body>>)
所以暂时停止将合适的元类视为元类,而将其视为 class。 每当你看到
suitable_metaclass('Name', (Base1,Base2), <<dict-built-by-body>>)
它告诉你合适的元类的__new__
方法必须有一个类似的签名
def __new__(metacls, name, bases, dct)
和一个__init__
方法
def __init__(cls, name, bases, dct)
所以签名并不完全相同,但它们仅在第一个参数上有所不同。
在元类中定义 class __init__
的最有效方法是什么?
你说的高效是什么意思? 除非您愿意,否则没有必要定义__init__
。
有没有办法在元类中引用 class 实例(通常是自我)?
不,你不应该这样做。 任何依赖于 class 实例的东西都应该在 class 定义中处理,而不是在元类中。
对于 1:任何class 的__init__
和__new__
都必须接受相同的 arguments,因为它们将使用相同的 arguments 调用。 It's common for __new__
to take more arguments that it ignores (eg object.__new__
takes any arguments and it ignores them) so that __new__
doesn't have to be overridden during inheritance, but you usually only do that when you have no __new__
at all .
这在这里不是问题,因为如前所述,元类总是使用同一组 arguments 调用,因此您不会遇到麻烦。 至少使用 arguments。 但是,如果您要修改传递给父 class 的 arguments,则需要同时修改它们。
对于 2:您通常不在元类中定义 class __init__
。 您可以编写一个包装器并在元类的__new__
或__init__
中替换 class 的__init__
,或者您可以在元类上重新定义__call__
。 如果您使用 inheritance,前者的行为会很奇怪。
import functools
class A(type):
def __call__(cls, *args, **kwargs):
r = super(A, cls).__call__(*args, **kwargs)
print "%s was instantiated" % (cls.__name__, )
print "the new instance is %r" % (r, )
return r
class B(type):
def __init__(cls, name, bases, dct):
super(B, cls).__init__(name, bases, dct)
if '__init__' not in dct:
return
old_init = dct['__init__']
@functools.wraps(old_init)
def __init__(self, *args, **kwargs):
old_init(self, *args, **kwargs)
print "%s (%s) was instantiated" % (type(self).__name__, cls.__name__)
print "the new instance is %r" % (self, )
cls.__init__ = __init__
class T1:
__metaclass__ = A
class T2:
__metaclass__ = B
def __init__(self):
pass
class T3(T2):
def __init__(self):
super(T3, self).__init__()
调用它的结果是:
>>> T1()
T1 was instantiated
the new instance is <__main__.T1 object at 0x7f502c104290>
<__main__.T1 object at 0x7f502c104290>
>>> T2()
T2 (T2) was instantiated
the new instance is <__main__.T2 object at 0x7f502c0f7ed0>
<__main__.T2 object at 0x7f502c0f7ed0>
>>> T3()
T3 (T2) was instantiated
the new instance is <__main__.T3 object at 0x7f502c104290>
T3 (T3) was instantiated
the new instance is <__main__.T3 object at 0x7f502c104290>
<__main__.T3 object at 0x7f502c104290>
对于 3:是的,来自__call__
,如上所示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.