为什么 __setattr__ 的“name”参数包含该类,而 __getattr__ 不包含该类?

StackOverflow https://stackoverflow.com/questions/2386418

  •  24-09-2019
  •  | 
  •  

下面的代码:

class MyClass():
    def test(self):
        self.__x = 0

    def __setattr__(self, name, value):
        print name

    def __getattr__(self, name):
        print name
        raise AttributeError(name)

x = MyClass()
x.test()
x.__y

输出:

_MyClass__x
__y
Traceback (most recent call last):
...
AttributeError: __y

该文档完全没有帮助,说明“名称”是“属性的名称”,但由于某种原因,它会有所不同,具体取决于您是设置它还是获取它。

我想知道的是:

  • 我在这里做的是根本错误的事情吗?
  • 如何得到 x 在第一种情况下而不是 _MyClass__x?
有帮助吗?

解决方案

双下划线调用名称修改。如果不需要名称修饰,请不要使用双取消划线

对象名称前的单下划线和双下划线的含义是什么?

来自 Python 文档

9.6。私有变量

Python 中不存在只能从对象内部访问的“私有”实例变量。然而,大多数 Python 代码都遵循一个约定:带有下划线前缀的名称(例如 _spam)应被视为 API 的非公共部分(无论是函数、方法还是数据成员)。它应被视为实施细节,如有更改,恕不另行通知。

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

请注意,损坏规则主要是为了避免事故而设计的;仍然可以访问或修改被视为私有的变量。这甚至在特殊情况下很有用,例如在调试器中。

请注意,代码传递到 exec, eval() 或者 execfile() 不认为调用类的类名是当前类;这类似于全局语句的效果,其效果同样仅限于字节编译在一起的代码。同样的限制适用于 getattr(), setattr()delattr(), ,以及引用时 __dict__ 直接地。

其他提示

我不确定为什么会发生这种情况,但是如果您使用 _x 而不是 __x 它可以按照您的期望工作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top