Python类中有“私有”变量吗?

756 投票
16 回答
690392 浏览
提问于 2025-04-15 15:28

我之前是学Java的,现在在看布鲁斯·埃克尔的《Python 3模式、食谱和习惯用法》。

在阅读关于类的内容时,书里提到在Python中不需要声明实例变量。你只需要在构造函数里使用它们,哗啦一下,它们就存在了。

举个例子:

class Simple:
    def __init__(self, s):
        print("inside the simple constructor")
        self.s = s

    def show(self):
        print(self.s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

如果这是真的,那么任何Simple类的对象都可以在类外部直接改变变量s的值。

比如说:

if __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

在Java中,我们学过公共/私有/受保护变量。这些关键词是有道理的,因为有时候你希望类里的变量是外部无法访问的。

那么在Python中为什么不需要这样做呢?

16 个回答

38

正如上面很多评论提到的,我们不要忘记访问修饰符的主要目的:帮助代码的使用者理解哪些部分是可以改变的,哪些部分是不应该改变的。当你看到一个私有字段时,就不要去动它。所以,这些修饰符大多数情况下只是语法上的一种装饰,Python中可以通过使用_和__来轻松实现。

249

在Python中,私有变量其实算是一种小技巧:解释器会故意给这个变量改个名字。

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

现在,如果你试图在类的定义外部访问 __var,那就会失败:

>>> x = A()
>>> x.__var # this will return error: "A has no attribute __var"

>>> x.printVar() # this gives back 123

不过,你可以很简单地绕过这个限制:

>>> x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

>>> x._A__var = 456 # you now know the masked name of private variables
>>> x.printVar() # this gives back 456

你可能知道,在面向对象编程中,方法是这样调用的:x.printVar() => A.printVar(x)。如果 A.printVar() 能访问到 x 中的某个字段,那么这个字段也可以在 A.printVar() 外部被访问……毕竟,函数是为了重复使用而创建的,里面的语句并没有什么特别的权限。

1158

这和文化有关。在Python中,你不会去修改其他类的实例变量或类变量。而在Java中,如果你真的想这么做,什么也阻止不了你——毕竟,你可以直接修改类的源代码来达到同样的效果。Python则不假装有这种安全性,它鼓励程序员要负责任。实际上,这种做法效果很好。

如果你出于某种原因想模拟私有变量,可以使用__前缀,具体可以参考PEP 8。Python会对像__foo这样的变量名进行处理,使得它们在包含它们的命名空间外不容易被看到(不过如果你真的想要,还是可以找到方法绕过这个限制,就像在Java中一样)。

同样的约定是,_前缀表示_variable应该仅在类(或模块)内部使用,即使技术上并没有阻止你从其他地方访问它。你不应该随便修改其他类的变量,比如__foo_bar

撰写回答