使用双下划线继承class属性

时间:2017-10-30 16:14:44

标签: python inheritance

我想我理解"名称错误的概念"在python中,但我可能错过了一些东西。看看下面的代码:

#!/usr/bin/env python

class Base(object):
    __data = "Base"

    @classmethod
    def func(cls):
        return "Class name is {}, data is {}".format(cls.__name__, cls.__data)


class A(Base):
    __data = "A"


class B(A):
    __data = "B"


print Base.func()
print A.func()
print B.func()

这是我得到的输出:

Class name is Base, data is Base
Class name is A, data is Base
Class name is B, data is Base

现在,我了解到,对于每个类,类属性的实际名称都会被修改为_<Class name>__data。例如,对于Base,它将是_Base__data,对于A,它将是_A__data等。

我的问题是,在func内,它正确识别了继承类(Base,A和B)的名称,但cls.__data始终指向cls._Base__data。这是为什么?我的意思是,如果__name__是A或B,那么我知道我在A或B类中,所以我希望cls.__data分别是A或B中的一个。我在这里缺少什么?

2 个答案:

答案 0 :(得分:2)

你并没有“失踪”,恰恰相反,你只是“发现”了什么名称的错误:它是为了确保方法内部具有双下划线的变量总是会看到与该方法在同一个类中定义的属性,而且没有任何子类。

如果您只是想在每个子类中使用该属性,那么这是所有其他属性的正常行为,但对于以两个下划线为前缀的属性。

所以,会发生的事情是.__data中使用的func名称本身在编译时被损坏为_base__data

答案 1 :(得分:1)

正如您所注意到的,用于名称修改的名称是方法声明的类的名称,而不是当前对象的派生类型。

The documentation for this feature明确地给出了一个关于从派生类保护变量的示例(而不是使用实例变量来保护外部代码)。

  

名称修改有助于让子类覆盖方法而不破坏类内方法调用。例如:

class Mapping:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update = update   # private copy of original update() method

class MappingSubclass(Mapping):

    def update(self, keys, values):
        # provides new signature for update()
        # but does not break __init__()
        for item in zip(keys, values):
            self.items_list.append(item)