访问私有类变量

5
在学习Python时,我遇到了这个奇怪的行为:
考虑下面这个简单的类:
class Human(object):
  def __init__(self, name):
    self.__name = name

  def description(self):
    print("Hello, my name is %s" % self.__name)

我希望避免在创建对象后能够更改名称。

如果我使用以下代码:

MyHuman = Human("Andy")
MyHuman.__name = "Arthur"
MyHuman.age = 23

MyHuman.description()
print MyHuman.age

在对象实例化之后,它不会更改名称,这很好,因为我希望实例变量是私有的。另一方面,我认为它会抱怨访问此变量。它甚至不会抱怨访问神秘的“age”变量,并且稍后正确地打印它。

我来自C#,这对我来说似乎很奇怪。我的错误在哪里?


4
你的错误在于认为Python中存在私有变量。最接近隐私的仿真是“不要注意幕后的那个变量”。如果有人真的想看看幕后,那就由他们自己决定。官方的说法是“同意的成年人”。 - TigerhawkT3
这里有关于Python对象和作用域的文档 - TigerhawkT3
在C#/ Java /等中,您不能动态创建变量吗? 就像 int age = 23;。Python允许您将这些变量放入任何对象的命名空间中,因为它非常方便。 - TigerhawkT3
我的意思是混淆的,而不是抱怨在类中访问不存在的变量,它会创建它... 如果你打错了,你不会注意到这个错误... 你明白吗? - Andy M
int age = 23 不是类成员。你故意创建了一个新的局部变量。这对我来说很重要... - Andy M
显示剩余4条评论
2个回答

10
您需要知道以下内容:
  1. 当您写入一个对象的不存在的属性时,python系统通常不会报错,而是会创建一个新属性。
  2. 私有属性并不受Python系统保护。这是设计决策。
  3. 私有属性将被掩盖。原因是避免继承链中出现冲突。掩盖是通过一些隐式重命名来完成的。私有属性将具有真实名称。
  "_<className>__<attributeName>"

使用该名称时,可以从外部访问。当从类内部访问时,名称将自动正确更改。


作为一名C#程序员,自动创建类成员对我来说有点令人不安。我会逐渐习惯的 :) 感谢您的解释和时间。 - Andy M
@AndyM:不客气。是的,Python确实有一些奇怪的地方,私有成员就是其中之一。你可以把它归因于Python是一种脚本语言,并为此感到自豪;设计师们想要事情变得明确,并且不想像其他语言那样拥有类型安全系统——它更多地依赖于开放性和清晰度。它强制执行较少,但依赖于用户的“良好行为”。 - Juergen

2
要在Python中模拟只读/私有变量,可以使用property语法。(评论/其他答案指出如果您知道如何访问变量,则仍然可以访问它 - 感谢您的提醒)。以下是一种方法:
>>> class Test:
        def __init__(self):
            self.__a = 1

        @property
        def a(self):
            return self.__a

>>> t = Test()
>>> t.a
1
>>> t.a = 2
AttributeError: cannot set attribute
>>> t.__a
AttributeError: 'Test' object has no attribute '__a'

2
>>> t._Test__a1 - TigerhawkT3
这个例子在Python 2.7和3.0上的行为可能不同吗?我的IDE使用的是Python 2.7,我没有收到错误消息并且允许t.a = 2。但是在在线3.0解释器上测试时,我得到了与您相同的错误... - Andy M
1
@AndyM 是的,那似乎很有可能。你尝试过将你的 Python 2 类定义为新式类,即 class Classname(object) 吗?这可能会有所不同。我不确定。 - Sam
@Sam 绝对正确。在我的类声明中添加 (object) 给了我正确的行为。非常有趣!感谢您的精确解释! - Andy M
@AndyM:我猜那就是问题所在。Python 2仍然支持“旧式类”——在某些属性区域,它们的行为完全不同。不同之处在于旧式类是像Sam一样启动的。据我所知,Python 3只支持新式类,因此它只是忽略了语法上的差异,我想。 - Juergen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接