我有两个超级班,父亲和母亲,他们将由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__()
s,我可以初始化父亲和母亲。
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)
Python中的多重继承需要合作。也就是说,两个父类需要知道彼此存在的可能性(尽管他们不需要知道彼此的任何细节)。然后,无论哪个父亲首先被命名,都可以调用另一个父母的__init__
方法。这就是super
的工作原理,它总是调用正在操作的实例的MRO中的下一个类(方法解析顺序)。
您的代码很难正确执行此操作,因为您总是在kwargs
调用中传递完整的super
字典。当第二个父亲试图调用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)
请注意,在Python 3中,您通常不需要将任何参数传递给super()
,它可以确定从哪个类调用并自动工作。在Python 2中,您必须指定当前类,但不再需要它。
最后一点。虽然我确信您的代码只是一个示例,但在OOP设计方面,类的名称非常差。继承意味着两个类之间的IS-A关系,这对人们来说并不合适。例如,在示例代码中创建的子代(Bart)不是Mother
或Father
,但代码说他是,因为他是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))
从这个link接受的答案:
通过super调用不会调用所有父项,它调用MRO链中的下一个函数。为了使其正常工作,您需要在所有
__init__s
中使用super
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__()