我有一个奇怪的元类问题。我正在使用一个元类来动态创建一个从另一个父类(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/

10-10 12:24