Python:如何使用super()初始化2个超类?

Python:如何使用super()初始化2个超类?,python,class,inheritance,subclass,superclass,Python,Class,Inheritance,Subclass,Superclass,我有两个超类,父亲和母亲,他们将由孩子继承 class Father: def __init__(self, **kwargs): self.fathername = kwargs["ffn"] + " " + kwargs["fln"] self.fatherage = kwargs["fa"] class Mother: def __init__(self, **kwargs): self.mothername = kwargs["mfn"] + " " +

我有两个超类,父亲和母亲,他们将由孩子继承

class Father:
  def __init__(self, **kwargs):
    self.fathername = kwargs["ffn"] + " " + kwargs["fln"]
    self.fatherage = kwargs["fa"]

class Mother:
  def __init__(self, **kwargs):
    self.mothername = kwargs["mfn"] + " " + kwargs["mln"]
    self.motherage = kwargs["ma"]
这个班的孩子继承自父母

class Child(Father, Mother):
  def __init__(self, **kwargs):
    self.name = kwargs["name"] + " " + kwargs["lastname"]
    self.age = kwargs["age"]
如果我分别调用它们的init,我可以初始化父和母

    Father.__init__(self, **kwargs)
    Mother.__init__(self, **kwargs)
但是我怎样才能用super达到同样的效果呢?如果我像下面这样称呼它,它只初始化父亲而不是母亲,因为我假设父亲是MRO中的下一个

    super().__init__(**kwargs)
下面是被覆盖的_str__,以显示分配的内容

def __str__(self):
    return \
    "Im {}, {} years old".format(self.name, self.age) + "\n" + \
    "My dad is {} and he is {} years old".format(self.fathername, self.fatherage) + "\n" + \
    "My mom is {} and she is {} years old".format(self.mothername, self.motherage)

familyname = "Simpson"
child = Child(**{"name": "Bart", "lastname": familyname, "age": 15, "ffn": "Hommer", "fln": familyname, "fa": 54, "mfn": "Marggie", "mln": familyname, "ma": 46})
当我尝试打印对象时,它将失败,因为当我在Child\uu init中使用super时,母超类从未初始化__

我还尝试将SuperMather、self.\uuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

Traceback (most recent call last):
  File "/tmp/pyadv.py", line 225, in <module>
    child = Child(**{"name": "Bart", "lastname": familyname, "age": 15, "ffn": "Hommer", "fln": familyname, "fa": 54, "mfn": "Marggie", "mln": familyname, "ma": 46})
  File "/tmp/pyadv.py", line 217, in __init__
    super().__init__(**kwargs)
  File "/tmp/pyadv.py", line 199, in __init__
    super(Father, self).__init__(**kwargs)
  File "/tmp/pyadv.py", line 208, in __init__
    super(Mother, self).__init__(**kwargs)
TypeError: object.__init__() takes no parameters
Traceback (most recent call last):
  File "/tmp/pyadv.py", line 225, in <module>
    child = Child(**{"name": "Bart", "lastname": familyname, "age": 15, "ffn": "Hommer", "fln": familyname, "fa": 54, "mfn": "Marggie", "mln": familyname, "ma": 46})
  File "/tmp/pyadv.py", line 217, in __init__
    super().__init__(**kwargs)
  File "/tmp/pyadv.py", line 199, in __init__
    super(Father, self).__init__()
  File "/tmp/pyadv.py", line 206, in __init__
    self.mothername = kwargs["mfn"] + " " + kwargs["mln"]
KeyError: 'mfn'

根据本文中的公认答案:

通过super调用并不会调用所有的父级,而是调用下一个父级 在MRO链中的功能。要使其正常工作,您需要使用 在所有的初始化中都是超级的


Python中的多重继承需要协作。也就是说,两个父类需要知道彼此存在的可能性,尽管它们不需要知道彼此的任何细节。然后,任何一个首先被命名的父级都可以调用另一个父级的uuu init_uuu方法。super就是这样工作的,它总是调用MRO中的下一个类,即正在操作的实例的方法解析顺序

您的代码很难正确执行此操作,因为您总是在超级调用中传递完整的kwargs dict。当第二个父对象试图调用MRO中的最后一个类object时,这就成了一个问题,该类不希望收到任何关键字参数。相反,每个类的_init _方法通常应该显式地命名它所期望的参数,并且在调用super._init _时不会再次传递这些参数,除非它知道它的父类之一也需要该参数

试试这个:

class Father:
  def __init__(self, ffn, fln, fa, **kwargs): # name the parameters we expect
    super().__init__(**kwargs)           # pass on any unknown arguments
    self.fathername = ffn + " " + fln    # use parameters by name, rather than via kwargs
    self.fatherage = fa

class Mother:
  def __init__(self, mfn, mln, ma, **kwargs):
    super().__init__(**kwargs)
    self.mothername = mfn + " " + mln
    self.motherage = ma

class Child(Father, Mother):
  def __init__(self, name, lastname, age, **kwargs):
    super().__init__(**kwargs)
    self.name = name " " + lastname
    self.age = age

    def __str__(self):
        return \
        "Im {}, {} years old".format(self.name, self.age) + "\n" + \
        "My dad is {} and he is {} years old".format(self.fathername, self.fatherage) + "\n" + \
        "My mom is {} and she is {} years old".format(self.mothername, self.motherage)


familyname = "Simpson"
child = Child(name="Bart", lastname=familyname, age=15, # you can use keyword syntax here
              ffn="Homer", fln=familyname, fa=54,
              mfn="Marge", mln=familyname, ma=46)
print(child)
请注意,在Python3中,通常不需要向super传递任何参数,它可以确定从哪个类调用它并自动工作。在Python2中,您必须指定当前的类,但这不再需要了

最后一个音符。虽然我确信您的代码只是一个示例,但在OOP设计中,类的名称非常糟糕。继承意味着这两个类之间存在一种IS-A关系,这种关系并不适合人。例如,在示例代码中创建的孩子Bart不是母亲或父亲,但代码说他是,因为他是母亲和父亲类的实例。描述与父母的人际关系更好的方法是HAS-A。每个孩子都有一个母亲和一个父亲。您可以使用封装建立HAS-A关系。这意味着,对于属性中的每个父对象,子对象都有一个对对象的引用。有趣的是,只要一门课就可以做到这一点,这可能就是为什么你没有学习这门课的原因,如果你在学习继承:

class Person:
    def __init__(self, firstname, lastname, age, father=None, mother=None):
        self.name = firstname + " " + lastname
        self.age = age
        self.father = father  #  set the attributes for our parents here
        self.mother = mother

fn = "Simpson"
bart = Person("Bart", fn, 15, Person("Homer", fn, 54), Person("Marge", fn, 46))

它不起作用了。我正在编辑问题以显示错误哇。太棒了。我不知道rettinger文章中的“脱衣”到底是什么意思。现在我了解到,对超类的每次调用都会删除dict所需的部分。最后,对象类会收到一个空dict。因此,我在他的文章中也了解了Root方法,并实现了它。如果有人愿意,我正在用根方法编辑我的问题。多谢各位
class Parent1(object):
    def __init__(self):
        super(Parent1, self).__init__()
        self.var1 = 1

class Parent2(object):
    def __init__(self):
        super(Parent2, self).__init__()
        self.var2 = 2

class Child(Parent1, Parent2):
    def __init__(self):
        super(Child, self).__init__()
class Father:
  def __init__(self, ffn, fln, fa, **kwargs): # name the parameters we expect
    super().__init__(**kwargs)           # pass on any unknown arguments
    self.fathername = ffn + " " + fln    # use parameters by name, rather than via kwargs
    self.fatherage = fa

class Mother:
  def __init__(self, mfn, mln, ma, **kwargs):
    super().__init__(**kwargs)
    self.mothername = mfn + " " + mln
    self.motherage = ma

class Child(Father, Mother):
  def __init__(self, name, lastname, age, **kwargs):
    super().__init__(**kwargs)
    self.name = name " " + lastname
    self.age = age

    def __str__(self):
        return \
        "Im {}, {} years old".format(self.name, self.age) + "\n" + \
        "My dad is {} and he is {} years old".format(self.fathername, self.fatherage) + "\n" + \
        "My mom is {} and she is {} years old".format(self.mothername, self.motherage)


familyname = "Simpson"
child = Child(name="Bart", lastname=familyname, age=15, # you can use keyword syntax here
              ffn="Homer", fln=familyname, fa=54,
              mfn="Marge", mln=familyname, ma=46)
print(child)
class Person:
    def __init__(self, firstname, lastname, age, father=None, mother=None):
        self.name = firstname + " " + lastname
        self.age = age
        self.father = father  #  set the attributes for our parents here
        self.mother = mother

fn = "Simpson"
bart = Person("Bart", fn, 15, Person("Homer", fn, 54), Person("Marge", fn, 46))