在使用元类崩溃之后,我深入研究了Python中元编程的主题,我有几个问题,即imho,在可用的文档中没有明确的答案。
__new__
和__init__
时,它们的参数必须定义相同?__init__
的最有效方法是什么?答案 0 :(得分:2)
同时使用__new__
和__init__
在元类中,他们的论点必须
定义相同吗?
我认为Alex Martelli解释道 它最简洁:
class Name(Base1,Base2): <<body>>
__metaclass__==suitable_metaclass
装置
Name = suitable_metaclass('Name', (Base1,Base2), <<dict-built-by-body>>)
所以不要再想了 proper_metaclass作为元类 暂时只是把它当作一个 类。每当你看到
suitable_metaclass('Name', (Base1,Base2), <<dict-built-by-body>>)
它告诉你
proper_metaclass的__new__
方法必须有签名
def __new__(metacls, name, bases, dct)
和<{p>}之类的__init__
方法
def __init__(cls, name, bases, dct)
所以签名不完全相同,但它们仅在第一个参数上有所不同。
什么是最有效的定义方式
元类中的类__init__
?
高效的是什么意思?它是
没有必要定义__init__
除非你想。
有没有办法引用课程 实例(通常是自我)在 元类?
不,你不应该这样做。 任何依赖于课程的东西 实例应该在 类定义,而不是在 元类。
答案 1 :(得分:1)
For 1:任何类的__init__
和__new__
必须接受相同的参数,因为它们将使用相同的参数进行调用。 __new__
采用它忽略的更多参数是很常见的(例如object.__new__
接受任何参数并忽略它们),因此在继承期间不必覆盖__new__
,但通常只有当你没有__new__
时才这样做。
这不是问题所在,因为正如所述,始终使用相同的参数集调用元类,因此您不会遇到麻烦。至少有论据。但是,如果要修改传递给父类的参数,则需要在两者中修改它们。
For 2:您通常不在元类中定义类__init__
。您可以编写包装器并替换元类的__init__
或__new__
中的类__init__
,也可以重新定义元类的__call__
。如果使用继承,前者会很奇怪。
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>
For 3:Yes,from __call__
,如上所示。