【问题标题】:Python class inheritance - Base is modified by a subclassPython 类继承 - Base 由子类修改
【发布时间】:2016-03-20 06:45:12
【问题描述】:

假设我有一个名为 Test 的类,其属性为 items。然后我创建了一个名为Best 的子类。其中有一个修改类属性项的方法。但它甚至修改了Testitems,而我只为Best 修改items

class Test():
    items = []

class Best(Test):
    def method(self):
        type(self).items.append("a test")

>>> Best().method()
>>> Best.items
["a test"]
>>> Test.items 
["a test"]            # This is what I don't want.

【问题讨论】:

  • Best 是否应该继承自 Test
  • 是的,我没有测试我的示例代码,抱歉。

标签: python class python-3.x inheritance


【解决方案1】:

您已将items 声明为超类本身的属性,因此 Test 的所有实例及其子类将共享同一个列表。而是在 Test 的 __ init __ 方法中声明它,因此每个实例都有一个列表。

在 Best 中,只需追加到 self.items,只会更新 Best 实例的列表。

class Test(object):
    def __ init __(self)
        self.items = []

class Best(Test):    # Best must inherit from Test
    def method(self):
        self.items.append("a test")

【讨论】:

  • 这将是它的实例而不是类的属性。
【解决方案2】:

在 Python 中,您可以通过使用“私人”成员来获得您所要求的内容...

class Base(object):
    def __init__(self):
        self.__mine = 42  # note the double underscore
    def baseMethod(self):
        return self.__mine

class Derived(Base):
    def __init__(self):
        Base.__init__(self)
        self.__mine = 99

    def derivedMethod(self):
        return self.__mine

obj = Derived()
print(obj.baseMethod(), obj.derivedMethod()) ## ==> 42, 99

这是因为在编译时Python会在编译Base时将名称__mine替换为_Base__mine,在编译Derived时替换为_Derived__mine

但是请注意,在 Python 中,虽然根据我的经验这是可能的,但它并不经常使用。由于“鸭子类型”和委托,在许多情况下不需要派生类,这在 C++ 或 Java 等语言中是不可能的。

【讨论】:

  • 好的,我会试试的。谢谢。
  • 这不是我想要的,但它仍然可以帮助我解决不同的问题,谢谢。
【解决方案3】:

唯一可能的方法是在子类上创建一个新的items——这个新列表还应该从哪里来? type(self) 也是多余的。如果在实例上找不到属性,查找机制会在类上查找属性。更好的是,如果您不需要实例,则将该方法声明为类方法。

例如。

class Test:
    items = []
    @classmethod
    def method_test(cls):
        cls.items.append('test')

class Best(Test):
    items = []
    @classmethod
    def method_best(cls):
        cls.items.append('best')

Test.method_test()

assert Test.items == ['test']
assert Best.items == []

Test.items = []
Best.method_test()
Best.method_best()

assert Test.items == []
assert Best.items == ['test', 'best']

请注意,当从 Best 类调用时,method_test 适用于 Best 类。

【讨论】:

    【解决方案4】:

    您的Best 类正在修改Test(我认为它应该继承自),因为Best 没有自己的items 列表。当您访问Best.items 时,您访问的是从其继承的列表(即从Test 类)。如果你想要一个不同的列表,你需要在子类Best中显式创建它:

    class Best(Test):
        items = [] # hide the inherited list with our own list
    
        # ...
    

    【讨论】:

      【解决方案5】:

      您的代码与您描述的不符。

      一方面,Best 不是Test 的子类。

      为另一个Best.method() 产生

      NameError: name 'self' is not defined
      

      itemsTest 类属性。

      t = Test()
      t.items.append(1)
      

      更改Test.items

      正如定义的B.items 给出AttributeError

      即使我改变:

      class Best():
          def method(self):
              ...
      

      Best.method() 不运行; method 是一个实例方法。我需要使用Best().method()。但后来我得到了itemsAttributeError

       class Best(Test):
          def method(self):
              ...
      

      做你想做的事。 Best().method() 修改了 Test.items - 因为 Test 类属性与子类共享。

      如其他答案所示,只需为Best 定义items 即可将其值与Test 类属性解耦

       class Best(Test):
           items = ['other']
           ...
      

      【讨论】:

      • 抱歉,我没有测试示例代码。我编辑了这个问题。谢谢。
      猜你喜欢
      • 2012-11-04
      • 1970-01-01
      • 1970-01-01
      • 2020-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多