我有一个奇怪的元类问题。我正在使用一个元类来动态创建一个从另一个父类(super class)继承的“同级”类,并将其分配为原始类的一个属性。以下是最小设置:
class Meta(type):
def __new__(cls, name, parents, dct):
sdct = dct.copy()
dct['sibling'] = type(name+'Sibling', (Mom,), sdct)
return super().__new__(cls, name, (Dad,), dct)
class Mom:
def __init__(self):
self.x = 3
class Dad:
def __init__(self):
self.x = 4
class Child(metaclass=Meta):
def __init__(self):
super().__init__()
self.y = 1 # <<< added from feedback
print(Child().x) # 4
print(Child().sibling) # <class '__main__.Child'> | should be ChildSibling
print(Child().sibling().x) # should be 3 instead throws:
# TypeError: super(type, obj): obj must be an instance or subtype of type
print(Child().sibling().y) # should print 4
上面创建“兄弟”类似乎出了点问题,但我不太确定该怎么办。我知道例如这将工作:
class ChildAbstract:
def __init__(self):
super().__init__()
ChildSibling = type('ChildSibling', (ChildAbstract, Mom), {})
Child = type('Child', (ChildAbstract, Dad), {'sibling': ChildSibling})
print(Child().sibling().x) # 3
我看不到这两种情况之间的区别。
最佳答案
传递给type的字典sdct包含__qualname__
,根据PEP,这是repr和str现在使用的。
尝试添加
print(Child is Child.sibling) # False
print(Child.sibling.__name__) # "ChildSibling"
您会发现它确实是 sibling 。
至于
sibling().x
抛出的原因,相同的sdct也已经包含Child.__init__
,最终成为动态创建的新类型__init__
的ChildSibling
。在对sibling()
的调用期间,super()
调用将类解析为Child
,并为其提供了ChildSibling
的实例:https://docs.python.org/3/library/functions.html#super
通过将第一个参数传递给方法作为实例来完成对当前实例的访问。
该错误在line 7210 of Object/typeobject.c处引发。
尝试使用以下命令删除
__init__
中的错误__new__
:del sdct['__init__']
现在
print(Child().sibling().x)
将打印3。
解决“泛型”继承和元编程的更友好的
__init__
的方法是使用super()
的2个参数形式:def __init__(self):
super(self.__class__, self).__init__()
关于Python元类继承问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36319601/