【问题标题】:Base class accessing super class variables基类访问超类变量
【发布时间】:2018-04-19 23:32:10
【问题描述】:

我正在使用 python 3.6。 我的目标是创建一个能够以某种方式通过多态访问的基类——子类变量之一。 我知道这听起来有点“不是 oop”,所以如果我描述的内容不能用 python 完成 - 我想知道这种情况下的最佳做法是什么。

按照维基百科的例子:

class Animal:
    def __init__(self, name):    # Constructor of the class
        self.name = name
    def talk(self):              # Abstract method, defined by convention only
        raise NotImplementedError("Subclass must implement abstract method")

class Cat(Animal):
    def talk(self):
        return 'Meow!'

class Dog(Animal):
    def talk(self):
        return 'Woof! Woof!'

animals = [Cat('Missy'),
           Cat('Mr. Mistoffelees'),
           Dog('Lassie')]

for animal in animals:
    print animal.name + ': ' + animal.talk()

打印以下内容:

Missy: Meow!
Mr. Mistoffelees: Meow!
Lassie: Woof! Woof!

我想获得完全相同的输出 - 使用 变量重载(这是一件事吗?)而不是方法重载。 原因是在我正在处理的程序中 - dogcat 和所有其他类型的 animal 将以完全相同的方式 talk - 仅受数据成员的影响,例如:

class Animal:
    def __init__(self, name):    # Constructor of the class
        self.name = name
        self.vocabulary = []     # so called abstract data member
    def talk(self):              # Non Abstract method, all animals would talk
        for word in self.vocabulary: print (word)

class Cat(Animal):
    vocabulary = ["Meow", "Muuuew", "Maow"]

class Dog(Animal):
    vocabulary = ["Woof", "Waf", "Haw"]

animals = [Cat('Missy'),
           Cat('Mr. Mistoffelees'),
           Dog('Lassie')]

for animal in animals:
    print animal.name + ': ' + animal.talk()

打印以下内容:

Missy: Meow Muuuew Maow
Mr. Mistoffelees: Meow Muuuew Maow
Lassie: Woof Waf Haw

显然,这不起作用,因为词汇表是空的,就像在基类中一样。 我尝试使用super 寻找解决方案,例如:

class Cat(Animal):
    vocabulary = ["Meow", "Muuuew", "Maow"]
    def talk(self):
        super(Animal,Cat).talk()

但结果会是AttributeError: 'super' object has no attribute 'talk'

我用super错了吗?

【问题讨论】:

  • 在您的示例中,vocabularyAnimal 的实例属性,但是 DogCat 的类属性。它实际上应该住在哪里?
  • 感谢您的评论,词汇应该是类属性,而不是实例变量。
  • 您的编辑过多地改变了问题的性质;我已经恢复了。如果您想要一个对类而不是实例进行操作的方法,请查找 classmethod

标签: python python-3.x oop inheritance polymorphism


【解决方案1】:

你的代码有一些未解决的问题,但是由于python是如此动态,它会通过正常的查找找到子类实例属性:

class Animal:
    def __init__(self, name):
        self.name = name

    def talk(self):
        for word in self.vocabulary: print (word)

class Cat(Animal):
    def __init__(self, name):
      super().__init__(name)
      self.vocabulary = ["Meow", "Muuuew", "Maow"]

class Dog(Animal):
  def __init__(self, name):
      super().__init__(name)
      self.vocabulary = ["Woof", "Waf", "Haw"]

animals = [Cat('Missy'),
           Cat('Mr. Mistoffelees'),
           Dog('Lassie')]

for animal in animals:
    print(animal.name, end=': ')
    animal.talk()

如果您希望在代码中更明确地执行此要求,您可以将Animal 设为抽象基类,并创建一个名为vocabulary 的抽象属性:

import abc

class Animal(abc.ABC):
    def __init__(self, name):
        self.name = name

    @property
    @abc.abstractmethod
    def vocabulary(self):
      ...

    def talk(self):
        for word in self.vocabulary: print (word)

class Cat(Animal):
    @property
    def vocabulary(self):
      return ["Meow", "Muuuew", "Maow"]

here is a live link

【讨论】:

  • abstractproperty 已弃用。现在推荐的方法是按这个顺序执行@property@abstractmethod(这是一个非常烦人的API,因为你必须记住这个顺序)。
  • 这很有帮助,但你可以将它应用到使用类变量吗?
【解决方案2】:

Python 是动态类型的。无需在Animal 中以某种方式声明“抽象数据成员”,以便Animal 方法引用self.vocabulary;事实上,您声明“抽象数据成员”的尝试导致了您的问题。

只需删除self.vocabulary = []talk 会在尝试访问self.vocabulary 时自动找到子类vocabulary

【讨论】:

  • 谢谢,我的问题不够清楚,我已对其进行了编辑,以表明我的目标是使用实例变量,而不是任何“自我”。
猜你喜欢
  • 2013-01-16
  • 1970-01-01
  • 2019-06-30
  • 1970-01-01
  • 2021-05-05
  • 2011-09-05
  • 2011-07-14
  • 1970-01-01
  • 2017-08-22
相关资源
最近更新 更多