Python中的多重继承
我刚开始学习Python语言,需要对我的代码进行点评,并解决我遇到的错误信息。
这段代码创建了一个名为Robot的类,它有两个父类:Transformer和Gundam。还有一个第三个类Hybrid,它从这两个类继承。我可以顺利地创建一个Transformer和一个Gundam,但创建Hybrid时却出现了错误。下面是代码和错误信息:
Main.py
from multiple_inheritance import Robot, Transformer, Gundam, Hybrid
tito = Gundam("Tito", "Japan")
optimus = Transformer("Optimus Prime", "Mars")
Jaeger = Hybrid("Striker", "US")
print(tito)
print(optimus)
multiple_inheritance
class Robot(object):
"""A robot class"""
def __init__(self, name):
self.name = name
def __str__(self):
return "{name}".format(name = self.name)
class Transformer(Robot):
"""A transformer"""
def __init__(self, name, planet):
self.planet = planet
super(Transformer, self).__init__(name)
def __str__(self):
return "Name = {name}, Planet = {planet}".\
format(name = self.name, planet = self.planet)
class Gundam(Robot):
"""A Gundam"""
def __init__(self, name, country):
self.country = country
super(Gundam, self).__init__(name)
def __str__(self):
return "Name = {name}, Country = {country}".\
format(name = self.name, country = self.country)
class Hybrid(Transformer, Gundam):
"""Ultimate Robot"""
错误信息
Traceback (most recent call last):
File "D:\Tech\Python\my_code\unit10\multiple_inheritance_main.py", line 5, in <module>
Jaeger = Hybrid("Striker", "US")
File "D:\Tech\Python\my_code\unit10\multiple_inheritance.py", line 13, in __init__
super(Transformer, self).__init__(name)
TypeError: __init__() missing 1 required positional argument: 'country'
2 个回答
Hybrid的类继承顺序看起来像这样:
>>> Hybrid.__mro__
(<class '__main__.Hybrid'>, <class '__main__.Transformer'>, <class '__main__.Gundam'>, <class '__main__.Robot'>, <type 'object'>)
你可以看到,在Transformer
之后,下一个类是Gundam
,而当你从Transformer
的__init__
方法调用它时,你传递的参数不够:
class Transformer(Robot):
"""A transformer"""
def __init__(self, name, planet):
self.planet = planet
#####This calls Gundam's __init__
super(Transformer, self).__init__(name)
所以,重点是super()
调用的是继承顺序中的下一个类,而不是你预期的Transformer
的基类。
这里有一篇很好的文章,和super()
有关:Python的super()被认为是超级的!
正如其他回答中提到的,Python 为你的类构建了一个方法解析顺序(MRO),这个顺序是 Hybrid -> Transformer -> Gundam -> Robot。这意味着,当你调用方法时,Python 会按照这个顺序去查找缺失的方法和属性。同时,这个顺序也会在使用 "super" 关键字时被遵循。
我不知道有没有人说过多重继承是“简单”的。由于多重继承带来的复杂性,Java 语言甚至完全不支持它。Python 通过 "super" 关键字和 MRO 概念让多重继承变得可用,但如果你在不同的父类的初始化方法中需要不同的关键字参数,每个类都必须知道如何处理它不认识的参数。
比如,Hybrid 类在调用时需要传入 "name"、"country" 和 "planet" 这三个参数,但 Transformer 类并不知道 "country" 是什么,Gundam 类也不知道 "planet" 是什么。
在 Python 中,你可以使用关键字参数来处理这个问题。你需要让中间类接受各种关键字参数,并使用它所知道的参数。在这种情况下,只需简单地改变类的 __init__
方法的签名,并对 super
调用做适当的调整:
class Robot(object):
"""A robot class"""
def __init__(self, name, **kwargs):
...
class Transformer(Robot):
"""A transformer"""
def __init__(self, name, planet, **kwargs):
...
super(Transformer, self).__init__(name, **kwargs)
class Gundam(Robot):
"""A Gundam"""
def __init__(self, name, country, **kwargs):
...
super(Gundam, self).__init__(name, **kwargs)
...
当然,当你实例化一个 Hybrid 时,你现在需要给参数命名:
my_robot = Hybrid("XYZ-Star", planet="Earth", country="Japan")