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

2024-09-22 16:25:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个超类,父亲和母亲,他们将由孩子继承。你知道吗

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

当我尝试打印对象时,它将失败,因为母超类从未初始化(当我在子类中使用__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)

Tags: nameinpyselfageinitisline
2条回答

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

您的代码很难正确执行此操作,因为您总是在super调用中传递完整的kwargsdict。当第二个父级试图调用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中,您必须指定当前类,但这不再需要了。你知道吗

最后一个音符。虽然我确信你的代码只是一个例子,但在面向对象设计方面,类的名称是非常糟糕的。继承意味着这两个类之间存在一种IS-A关系,这实际上并不适合人。例如,在示例代码(Bart)中创建的子级不是MotherFather,但是代码说他是,因为他是MotherFather类的实例。描述与父母之间人际关系的更好方法是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))

根据本link中的公认答案:

Invocation via super doesn't call all the parents, it calls the next function in the MRO chain. For this to work properly, you need to use super in all of the __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__()

相关问题 更多 >