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

时间:2018-09-02 12:33:49

标签: python class inheritance subclass superclass

我有两个父类,父亲和母亲,它们将由Child继承。

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})

当我尝试打印对象时,它将失败,因为母亲超类从未被初始化(当我在子super()中使用__init__()时)

print(child)

The program raises a runtime error

Traceback (most recent call last):
  File "/tmp/pyadv.py", line 225, in <module>
    print(child)
  File "/tmp/pyadv.py", line 217, in __str__
    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)
AttributeError: 'Child' object has no attribute 'mothername'

那么,如何使用super初始化两个超类?

编辑: 我试图将super(Father, self).__init__(**kwargs)super(Mother, self).__init__(**kwargs)添加到超类__init__()方法中,但是出现以下错误:

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

我还尝试将super(Father, self).__init__()super(Mother, self).__init__()__init__()中没有参数)添加到超类__init__()方法中,但随后出现以下错误:

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'

解决方案1: @blkkngt剥离以下

解决方案2: 根超类,详细here

class Root:
  def __init__(self, **kwargs):
    pass

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

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

class Child(Father, Mother):
  def __init__(self, **kwargs):
    self.name = kwargs["name"] + " " + kwargs["lastname"]
    self.age = kwargs["age"]
    super().__init__(**kwargs)
  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": "Homer", "fln": familyname, "fa": 54, "mfn": "Marge", "mln": familyname, "ma": 46})

print(child)

2 个答案:

答案 0 :(得分:1)

Python中的多重继承需要合作。也就是说,两个父类需要意识到彼此存在的可能性(尽管他们不需要知道彼此的任何细节)。然后,首先指定哪个父对象可以调用另一个父对象的__init__方法。 super就是这样工作的,它总是在被操作实例的MRO(方法解析顺序)中调用下一个类。

由于您总是在kwargs调用中传递完整的super格,因此您的代码很难正确执行此操作。当第二个父级尝试调用MRO中的最后一个类object时,这将成为问题,该MRO不会收到任何关键字参数。相反,每个类的__init__方法通常应显式命名其期望的参数,并且在调用super().__init__时不要再次传递它们(除非它知道其父类之一也需要该参数)。 / p>

尝试一下:

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)

请注意,在Python 3中,通常不需要将任何参数传递给super(),它可以弄清楚从哪个类中调用它并可以自动工作。在Python 2中,您必须指定当前的类,但这不再需要。

最后的笔记。虽然我确定您的代码只是一个示例,但在进行OOP设计时,这些类的名称却很贫乏。继承意味着两个类之间的 IS-A 关系,这实际上并不适合人们。在示例代码中,例如(Bart)创建的子级不是MotherFather,但是代码表明他是,因为他是Mother和{ Father类。描述与父母之间的人际关系的一种更好的方法是 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))

答案 1 :(得分:0)

从此link中接受的答案开始:

  

通过super调用不会调用所有父级,而是调用下一个父级   在MRO链中发挥作用。为了使其正常工作,您需要使用   在所有__init__s

中都是超级
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__()