python3菱形继承如何为数据字段工作?如何用super()._init__初始化继承的字段? &g



我正在检查这个问题,以理解多重继承,我被卡住了。如何设置从上一个类继承的对象的字段?

class Vehicle():
def __init__(self, name:str, seats:int):
self.name = name
self.seats = seats
def print_vehicle(self):
print(f'Vehicle {self.name} has {self.seats} seats')
class Boat(Vehicle):
def __init__(self, name:str, seats:int, engine_type:str):
super().__init__(name, seats)
self.engine_type = engine_type
def print_vehicle(self):
print(f'Boat {self.name} has {self.seats} seats and engine {self.engine_type}')
class Car(Vehicle):
def __init__(self, name:str, seats:int, fuel:str):
super().__init__(name, seats)
self.fuel = fuel
def print_vehicle(self):
print(f'Car {self.name} has fuel {self.fuel}')
class AnphibiousCar(Boat, Car):
def __init__(self, name, seats, engine_type, fuel):
super(AnphibiousCar, self).__init__(name, seats, engine_type) # ???

def print_vehicle(self):
print(f'Anphibious car {self.name} has {self.seats} seats and {self.engine_type} - {self.fuel} engine')

ac = AnphibiousCar('name', 4, 'piston', 'gas')
ac.print_vehicle()

关键是每个类应该只关注对其直接负责的事务;剩下的应该是委托的超类(并且注意,当你处理与super()合作继承时,调用super()的方法不需要知道实际的超类是什么,特别是最接近的一个-因为这可能会改变,取决于self的实际类)。

那么让我们重新实现你的类(在评论中有一堆解释):

class Vehicle:
# Added the `*,` marker to make `name` and `seats` *keyword-only*
# arguments (i.e., arguments that are identified only by their
# *names*, never by their positions in a call's arguments list).
def __init__(self, *, name: str, seats: int):
self.name = name
self.seats = seats
# We abstract out class-specific features into separate methods,
# keeping in the `print_vehicle()` method only the common stuff,
# so that in subclasses we'll need to customize only those methods
# (`list_features()`, `get_type_label()`), *not* `print_vehicle()`.
def print_vehicle(self):
vehicle_type_label = self.get_type_label()
features = ', '.join(self.list_features())
print(f'{vehicle_type_label} {self.name}: {features}.')
# Side note: the `list[str]` type annotation requires Python 3.9
# or newer (for compatibility with older versions you need to
# replace it with `List[str]`, using `from typing import List`).
def list_features(self) -> list[str]:
return [f'has {self.seats} seats']
# This implementation is, in fact, quite generic (so that
# in most subclasses we will *not* need to customize it).
def get_type_label(self) -> str:
return self.__class__.__name__

class Boat(Vehicle):
# Only `Boat`-specific arguments (as keyword-only ones, as above...)
# are declared here explicitly. Any other are treated as a "black
# box", just being passed into superclasses...
def __init__(self, *, engine_type: str, **kwargs):
super().__init__(**kwargs)
self.engine_type = engine_type
# Also here we focus only on this-class-specific stuff, handling
# other stuff as "agnostically" as possible...
def list_features(self) -> list[str]:
return super().list_features() + [f'has {self.engine_type} engine']

class Car(Vehicle):
# And analogously...
def __init__(self, *, fuel: str, **kwargs):
super().__init__(**kwargs)
self.fuel = fuel
def list_features(self) -> list[str]:
return super().list_features() + [f'needs {self.fuel} fuel']

class AmphibiousCar(Boat, Car):
# Note: here we get our `__init__()` and `list_features()`
# for free (!), as the superclasses provide all we need
# when it comes to those two methods.
# The only thing we may want to customize is:
def get_type_label(self) -> str:
return 'Amphibious car'

ac = AmphibiousCar(
name='Julia-III',
seats=4,
engine_type='piston',
fuel='gas')
# "Amphibious car Julia-III: has 4 seats, needs gas fuel, has piston engine."
ac.print_vehicle()

作为进一步的阅读,我建议:https://rhettinger.wordpress.com/2011/05/26/super-considered-super/

你有一些错误:

  • super(AnphibiousCar, self).__init__(name, seats, engine_type)可以变成Boat.__init__(self, name, seats, engine_type)所以调用类你可以给出如何初始化的信息。
  • Boat中缺少一个参数,您应该给出fuel参数到超类Vehicle,如super().__init__(name, seats, "oil")

你可以注意到,如果你使用super,你不需要传递self,如果你使用您正在使用的类名。

我的观点是,是的,理解是好的,但不要失去太多时间作为这种多重继承只是理论上和实践上的在实际编码中没有使用。这实际上会造成很多混淆和添加样板…"new"像Rust这样的语言甚至不提供继承。只是说:"是的,学习它,但要保持简单"。^ _ ^

最新更新