python元类继承问题

Buc*_*uck 4 python inheritance metaclass

我有一个奇怪的元类问题.我正在使用元类来动态创建一个继承自另一个超类的"兄弟"类,并将其作为原始类的属性赋值.以下是最小化设置:

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
Run Code Online (Sandbox Code Playgroud)

随着"兄弟"课程的创作,上面似乎出现了一些问题,但我不太确定是什么.我知道例如这会起作用:

class ChildAbstract:
    def __init__(self):
        super().__init__()

ChildSibling = type('ChildSibling', (ChildAbstract, Mom), {})
Child = type('Child', (ChildAbstract, Dad), {'sibling': ChildSibling})
print(Child().sibling().x) # 3
Run Code Online (Sandbox Code Playgroud)

但我看不出两种情况之间的区别.

Ilj*_*ilä 5

字典sdct传递给type includes __qualname__,根据这个PEP,reprstr现在使用了.

尝试添加

print(Child is Child.sibling)  # False
print(Child.sibling.__name__)  # "ChildSibling"
Run Code Online (Sandbox Code Playgroud)

你会发现它确实是兄弟姐妹.

至于为什么sibling().x抛出,同样的sdct也已经包含Child.__init__,它最终是__init__动态创建的新类型ChildSibling.在对调用sibling()super()调用期间,将类解析为,Child并且给出了以下实例ChildSibling:

另请注意,除零参数形式外,super()不限于使用内部方法.两个参数形式完全指定参数并进行适当的引用.零参数形式仅适用于类定义,因为编译器填写必要的细节以正确检索正在定义的类,以及访问普通方法的当前实例.

https://docs.python.org/3/library/functions.html#super

通过将第一个参数传递给method as instance来完成对当前实例的访问.

super() -> same as super(__class__, <first argument>)

Object/typeobject.c的第7210行引发错误.

尝试删除__init__你的错误__new__:

del sdct['__init__']
Run Code Online (Sandbox Code Playgroud)

现在

print(Child().sibling().x)
Run Code Online (Sandbox Code Playgroud)

将打印3.

"泛型"继承和元编程更友好的解决方案__init__是使用以下2参数形式super():

def __init__(self):
    super(self.__class__, self).__init__()
Run Code Online (Sandbox Code Playgroud)

  • 所以`super().__ init __() - > super(self .__ class__,self).__ init __()`sovles this,thanks @Ilja (2认同)