首页 > 解决方案 > 为什么子类访问超类的属性,尽管当该属性被声明为私有时,它有自己的同名属性?

问题描述

我有一个父类Animal和一个子类Dog。我想为每个创建 1 个实例并打印它们的count。这是工作代码:

class Animal:
  count=0
  def __init__(self):
     Animal.count+=1
  @classmethod
  def getCount(cls):
     return cls.count

class Dog (Animal):
  count=0
  def __init__(self):
    super().__init__()
    Dog.count+=1

 a1=Animal()
 print(Animal.getCount(),Dog.getCount())
 d1=Dog()
 print(Animal.getCount(),Dog.getCount())

它打印:
1 0
2 1

这是正确的,因为有 2 只动物,但其中只有 1 只是狗。

当我将计数变量创建为私有__count而不更改任何其他代码时,就会出现问题。

class Animal:
  __count=0
  def __init__(self):
    Animal.__count+=1
  @classmethod
  def getCount(cls):
    return cls.__count

class Dog (Animal):
  __count=0
  def __init__(self):
    super().__init__()
    Dog.__count+=1

a1=Animal()
print(Animal.getCount(),Dog.getCount())
d1=Dog()
print(Animal.getCount(),Dog.getCount())



现在,它打印:
1 1
2 2

似乎Dog类只访问Animal 的 __count
你能检测出代码中的错误吗?

标签: pythonoop

解决方案


简短的回答

当一个属性是私有的,例如__count,这意味着它只能从同一个类中访问。Animal.__count只能在 内访问Animal,并且Dog.__count只能在 内访问Dog

因为getCount在 中定义Animal,它只能访问Animal.__count,所以这就是它返回的内容。

如果要访问子类的“私有”变量,请使用单个下划线前缀,例如_count.

相关阅读:

详细介绍

私有变量是通过一种名为name mangling的机制来实现的。从文档

由于类私有成员有一个有效的用例(即避免名称与子类定义的名称发生名称冲突),因此对这种机制的支持有限,称为name mangling形式的任何标识符__spam(至少两个前导下划线,最多一个尾随下划线)在文本上替换为 _classname__spam,其中classname是当前类名,前导下划线被剥离。只要它出现在类的定义中,就无需考虑标识符的句法位置,就可以完成这种修饰。

这意味着您的代码被翻译成这样:

class Animal:
    _Animal__count = 0

    def __init__(self):
        Animal._Animal__count += 1

    @classmethod
    def getCount(cls):
        return cls._Animal__count

class Dog(Animal):
    _Dog__count = 0

    def __init__(self):
        super().__init__()
        Dog._Dog__count += 1

如果你这样看,很明显getCount无法访问Dog's__count变量。


推荐阅读