Python 关于子类化的问题

Python 关于子类化的问题,python,python-3.x,Python,Python 3.x,我整个上午都在读关于子类化的书,但仍然有一些问题。假设我们有以下类别的汽车: 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

我整个上午都在读关于子类化的书,但仍然有一些问题。假设我们有以下类别的汽车:

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
这是行不通的。有几个问题:

  • 如果我们使用
    super()
  • 在这种情况下,电动汽车不需要气体值;我们需要从汽车继承此属性吗
  • 当我们使用super()时,是否需要引用父类构造函数的所有属性?对于电动汽车,我们是否需要编写:
    super()。\uuuu init\uuuu(汽油,英里)

  • 回答您的问题:

    通过将
    Car
    子类化为
    ElectricCar
    ,您可以创建一个名为“ElectricCar”的新类,该类除了添加到
    ElectricCar
    中的内容外,还包含Car类的所有属性、属性和功能。电动汽车是一辆汽车和其他东西。通过调用
    super()。\uuuuu init\uuuuu
    在这种情况下,您正在调用类的父类
    上的构造函数(函数)。出现错误是因为此函数需要两个参数:
    gas
    miles
    ,但您只提供一个。调用任何方法时,必须提供该方法所需的所有参数


    在您的情况下,您的
    电动汽车
    不需要
    汽油
    ,因为它代表电动汽车。但是,在Python中,您没有选择说,“我想从
    Car
    继承这个,但不是那个”。因此,您的架构存在问题,因为您假设汽车的基本情况是汽油车。因此,您应该从
    Car
    中删除
    gas
    属性,并创建一个封装该信息的
    GasolineCar

    要回答您的问题:

    通过将
    Car
    子类化为
    ElectricCar
    ,您可以创建一个名为“ElectricCar”的新类,该类除了添加到
    ElectricCar
    中的内容外,还包含Car类的所有属性、属性和功能。电动汽车是一辆汽车和其他东西。通过调用
    super()。\uuuuu init\uuuuu
    在这种情况下,您正在调用类的父类
    上的构造函数(函数)。出现错误是因为此函数需要两个参数:
    gas
    miles
    ,但您只提供一个。调用任何方法时,必须提供该方法所需的所有参数


    在您的情况下,您的
    电动汽车
    不需要
    汽油
    ,因为它代表电动汽车。但是,在Python中,您没有选择说,“我想从
    Car
    继承这个,但不是那个”。因此,您的架构存在问题,因为您假设汽车的基本情况是汽油车。因此,您应该从
    Car
    中删除
    gas
    属性,并创建一个封装该信息的
    GasolineCar

    我们来举一个非常简单的例子:

    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
    所有属性,而不是专门添加或覆盖的属性

    为了演示,可以使用来显示每个实例的属性。(我过滤掉了内部方法和属性,只关注用户属性):

    您可以在
    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
    Bar
    中的
    \uuuuu init\uuuu
    中删除,则
    Foo
    中的
    \uuuu init\uuuu
    将永远不会被调用。结果是可见的,与
    Foo
    中的
    \uuuuu init\uuuu
    相关的隐式代码(如实例值的赋值)未完成:

    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
    中的实例属性不会作为属性添加到
    Bar
    的实例中(以及添加到
    Foo
    的实例中的任何其他特定添加):


    我们来举一个非常简单的例子:

    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
    所有属性,而不是专门添加或覆盖的属性

    为了演示,可以使用来显示每个实例的属性。(我过滤掉了内部方法和属性,只关注用户属性):

    您可以在
    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
    Bar
    中的
    \uuuuu init\uuuu
    中删除,则
    Foo
    中的
    \uuuu init\uuuu
    将永远不会被调用。结果是可见的,与
    Foo
    中的
    \uuuuu init\uuuu
    相关的隐式代码(如实例值的赋值)未完成:

    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
    中的实例属性不会作为属性添加到
    Bar
    的实例中(以及添加到
    Foo
    的实例中的任何其他特定添加):


    看看类属性、实例属性和默认值之间的区别。您可以继承属于该类的所有属性。这包括可以设置实例属性的方法,如init,除非它被重写。是的,当您调用super()时,必须向它传递正确的参数。所有继承本质上都是在方法解析期间检查基类。因此,当您执行
    myobject.some_attribute
    时,首先检查实例名称空间的
    some_attribute
    ,然后检查类名称空间,然后按方法解析顺序检查所有类名称空间。这种继承似乎是错误的。
    Car
    类应该定义每单位“燃料”的最大速度、加速度、行驶距离(不限制wha)