【问题标题】:Python 2.7 multiple inheritancePython 2.7 多重继承
【发布时间】:2017-12-18 18:05:22
【问题描述】:

为什么这个简单的代码不适用于 Python 2.7?请帮忙。很可能我在类的“新样式”中滥用super 方法。

class Mechanism(object):
    def __init__(self):
        print('Init Mechanism')
        self.__mechanism = 'this is mechanism'

    def get_mechanism(self):
        return self.__mechanism

class Vehicle(object):
    def __init__(self):
        print('Init Vehicle')
        self.__vehicle = 'this is vehicle'

    def get_vehicle(self):
        return self.__vehicle

class Car(Mechanism, Vehicle):
    def __init__(self):
        super(Car, self).__init__()

c = Car()
print(c.get_mechanism())
print(c.get_vehicle())

错误:

Init Vehicle
Traceback (most recent call last):
  File "check_inheritance.py", line 22, in <module>
    print(c.get_mechanism())
  File "check_inheritance.py", line 7, in get_mechanism
    return self.__mechanism
AttributeError: 'Car' object has no attribute '_Mechanism__mechanism'

编辑

  1. Mechanism 类中的def __init(self): 固定到def __init__(self):
  2. 正确答案是在所有类中使用super 方法。不仅在Car 类中。见Martijn Pieters的回答
  3. 尽量避免对私有变量使用双下划线__。它不是 Python 方式(代码风格)。 See the discussion for more info here

【问题讨论】:

  • 你的机制初始化拼写错误,前后应该有两个下划线
  • 这里还误用了super:按照目前的结构,Vehicle.__init__ 方法不会被调用。您需要一个公共根类(VehicleMechanism 的基类),所有子类,包括 VehicleMechanism 都应该调用 super
  • @MartijnPieters:我认为除了拼写错误的 __init__ 方法之外,这里还有一个关于使用 super 的有效问题。
  • 在这种情况下,您只是打错了字,并且您忘记调用链中的下一个 __init__ 方法,因此没有调用 Mechanism 的初始化程序有两个不同的原因。你真的不应该使用前导双下划线属性,除非你正在为第 3 方构建一个框架来扩展,请参阅Inheritance of private and protected methods in Python
  • 您必须在 所有 子类中调用 super 才能使协作式多重继承正常工作。然后私有变量就可以正常工作了。

标签: python python-2.7 inheritance multiple-inheritance


【解决方案1】:

您有 2 个问题:

  • 您将Mechanism__init__ 方法命名错误;您缺少两个下划线。

  • 您的__init__ 方法在多重继承情况下不能正确协作。确保在您的__init__ 方法中所有始终调用super(...).__init__()

以下代码有效:

class Mechanism(object):
    def __init__(self):
        super(Mechanism, self).__init__()
        print('Init Mechanism')
        self.__mechanism = 'this is mechanism'

    def get_mechanism(self):
        return self.__mechanism

class Vehicle(object):
    def __init__(self):
        super(Vehicle, self).__init__()
        print('Init Vehicle')
        self.__vehicle = 'this is vehicle'

    def get_vehicle(self):
        return self.__vehicle

class Car(Mechanism, Vehicle):
    def __init__(self):
        super(Car, self).__init__()

演示:

>>> c = Car()
Init Vehicle
Init Mechanism
>>> print(c.get_mechanism())
this is mechanism
>>> print(c.get_vehicle())
this is vehicle

您可能还应该使用双下划线名称。有关详细信息,请参阅Inheritance of private and protected methods in Python,但简短的原因是您在这里没有类私有名称的用例,因为您没有构建一个旨在由第三方扩展的框架;这是此类名称的唯一真正用例。

改用单下划线名称,如_mechanism_vehicle

【讨论】:

  • 啊!我懂了。我必须在所有课程中使用super(...).__init__()。谢谢你,马丁!您的更改正在发挥作用。
  • 致 Martijn -- 也许我陷入了 C++ 风格,但我的意见是让所有变量在类中都是私有的。我说的不对吗?
  • @foobar:您确实陷入了 C++ 风格。 Python 没有隐私模型; all 属性可用于在解释器中运行的所有代码。类“私有”属性只给定一个自动命名空间,仅此而已。该自动命名空间(添加了单个前导下划线的类名)用于防止与子类中的属性发生冲突,而不是使名称无法从外部访问。
  • @foobar:Python 风格是不使用访问器,而是让属性成为一流的公共 API。所以不要使用c.get_mechanism(),而是使用c.mechanism(公共属性)。
  • @foobar:我不知道为什么 C++ 更喜欢 getter 和 setter,但我知道在 Java 中很难将 API 从公共属性转换为 getter和后来的二传手。因此,为了避免这种过渡的痛苦,不管怎样,指导原则是始终使用 getter 和 setter。在 Python 中,将属性转换为 property 对象(Pythonic getter-setter 模式)是微不足道的,因此您永远不必担心未来的选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-14
  • 1970-01-01
  • 2020-12-18
  • 2021-08-05
  • 1970-01-01
  • 1970-01-01
  • 2021-05-16
相关资源
最近更新 更多