我整个上午都阅读过有关子类化的知识,但仍然有一些问题。假设下面有Car类:
class Car():
doors=4
color='red'
def __init__(self,gas,miles):
self.gas=gas
self.miles=miles
@property #responsible for handing back the value of the variable gas
def gas(self):
return self._gas
@gas.setter #responsible for setting the value of the variable gas
def gas(self,x):
if x<0:
raise ValueError('Gas cannot be negative')
self._gas=x
使用门和颜色的默认值实例化该类。我们还使用装饰器检查gas的值是否为负。这一切对我来说都是有意义的。但是,假设我们创建了一个ElectricCar子类:
class ElectricCar(Car):
def __init__(self,battery_charge,miles):
self.battery_charge=battery_charge
super().__init__(miles)
这不起作用。一些问题:
super().__init__
,是否可以从父类继承所有属性?super().__init__
时是否需要引用父类构造函数的所有属性?对于ElectricCar,我们是否需要编写:super().__init__(gas, miles)
?答案 0 :(得分:4)
要回答您的问题:
通过将Car
用ElectricCar
子类化,您创建了一个名为“ ElectricCar”的新类,除了添加到{{1}上的所有内容之外,该类还包含Car类的所有属性,属性和功能。 }。电动车是汽车,还有更多。通过调用ElectricCar
,您可以在类的父类{在本例中为super().__init__
上调用构造函数(__init__
函数)。您会收到错误消息,因为此函数需要两个参数:Car
和gas
,但是您只提供了一个。调用任何方法时,您必须提供该方法的所有必需参数。
在您的情况下,您的miles
不需要ElectricCar
,因为它代表的是电动汽车。但是,在Python中您没有选择说“我想从gas
继承这个,但不是那个”。因此,您的体系结构存在问题,因为您假设汽车的基本情况是汽油车。因此,应该从Car
中删除gas
属性,并创建一个封装该信息的Car
类。
答案 1 :(得分:1)
让我们举一个非常简单的例子:
class Foo:
ca1="a class attribute in Foo"
def __init__(self, dv1, dv2="a default value"):
self.ia="an instance attribute in Foo"
self.dv1=dv1
self.dv2=dv2
class Bar(Foo):
ca2="a class attribute in Bar"
def __init__(self, dv="new default from Bar"):
self.ia="an instance attribute in Bar"
super().__init__("from Bar 1", dv)
Bar
的任何实例都将从Foo
继承所有 而不是专门添加或覆盖的属性。
为了演示,您可以使用inspect module来显示每个实例的属性。 (我正在过滤内部方法和属性,仅关注用户属性):
>>> import inspect
>>> [a for a in inspect.getmembers(Foo("positional argument"), lambda at: not(inspect.isroutine(at))) if not(a[0].startswith('__'))]
[('ca1', 'a class attribute in Foo'),
('dv1', 'positional argument'),
('dv2', 'a default value'),
('ia', 'an instance attribute in Foo')] # I added the new lines...
您可以在Foo
的实例中看到类和实例变量。
现在来看一个Bar
的实例:
>>> [a for a in inspect.getmembers(Bar(), lambda at: not(inspect.isroutine(at))) if not(a[0].startswith('__'))]
[('ca1', 'a class attribute in Foo'),
('ca2', 'a class attribute in Bar'),
('dv1', 'from Bar 1'),
('dv2', 'new default from Bar'),
('ia', 'an instance attribute in Foo')]
如果从super
的{{1}}中删除__init__
,则永远不会调用Bar
中的__init__
。结果是可见的,与Foo
中的__init__
相关的隐式代码(如实例值的分配)未完成:
Foo
区别在于class Bar(Foo):
ca2="a class attribute in Bar"
def __init__(self, dv="new default from Bar"):
self.ia="an instance attribute in Bar"
中的实例属性不会作为属性添加到Foo
的实例中(以及对{{1}的实例所做的任何其他特定添加) }):
Bar