我来自Java世界,正在阅读Bruce Eckels的《Python 3 Patterns, Recipes and idiom》。

在阅读有关类的内容时,会继续说在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中不需要这个?


当前回答

我唯一一次使用私有变量是当我需要在写入或读取变量时做其他事情,因此我需要强制使用setter和/或getter。

正如前面所述,这又涉及到文化。我一直在工作的项目中,读取和写入其他类变量是自由的。当一个实现被弃用时,识别使用该函数的所有代码路径需要更长的时间。当强制使用setter和getter时,可以很容易地编写调试语句来识别已调用的废弃方法和调用它的代码路径。

当你在一个任何人都可以编写扩展的项目中,通知用户那些将在几个版本中消失的废弃方法,因此在升级时将模块破坏降到最低是至关重要的。

所以我的答案是;如果您和您的同事维护一个简单的代码集,那么保护类变量并不总是必要的。如果您正在编写一个可扩展的系统,那么当对核心的更改需要被使用该代码的所有扩展捕获时,它就变得必不可少。

其他回答

“在java中,我们学习了公共/私有/受保护变量”

“为什么在python中不需要这个?”

出于同样的原因,它在Java中不是必需的。

您可以自由使用或不使用private和protected。

作为Python和Java程序员,我发现私有和受保护是非常非常重要的设计概念。但实际上,在数万行Java和Python代码中,我从未真正使用过private或protected。

为什么不呢?

我的问题是"被谁保护?"

我团队中的其他程序员?他们有消息来源。当他们可以改变的时候,保护意味着什么?

其他团队的其他程序员?他们在同一家公司工作。只要打个电话,他们就能找到线人。

客户吗?这是一种雇佣式编程(通常)。客户机(通常)拥有代码。

那么,我到底在保护谁呢?

它的文化。在Python中,不写入其他类的实例或类变量。在Java中,如果你真的想这样做,没有什么可以阻止你这样做——毕竟,你总是可以编辑类本身的源代码来达到同样的效果。Python放弃了安全的伪装,并鼓励程序员负责任。在实践中,这工作得非常好。

如果您出于某种原因想要模拟私有变量,您总是可以使用PEP 8中的__前缀。Python会修改像__foo这样的变量名,这样它们就不容易被包含它们的命名空间之外的代码看到(尽管如果你足够坚定,你可以绕过它,就像你可以绕过Java的保护一样)。

根据同样的约定,_前缀意味着_variable应该只在类(或模块)内部使用,即使技术上不阻止从其他地方访问它。你不会摆弄其他类的变量,比如__foo或_bar。

下面是我处理Python 3类字段的方法:

class MyClass:
    def __init__(self, public_read_variable, private_variable):
        self.public_read_variable_ = public_read_variable
        self.__private_variable = private_variable

我只在MyClass方法中使用两个下划线访问__private_variable。

我用一个下划线对public_read_variable_进行读访问 在类之外,但从不修改变量:

my_class = MyClass("public", "private")
print(my_class.public_read_variable_) # OK
my_class.public_read_variable_ = 'another value' # NOT OK, don't do that.

私有变量在Python中或多或少是一种hack:解释器会故意重命名变量。

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

你可能知道OOP中的方法是这样调用的:x. printvar () => A.printVar(x)。如果A.printVar()可以访问x中的某个字段,那么这个字段也可以在A.printVar()之外访问…毕竟,函数是为可重用性而创建的,其中的语句并没有任何特殊的功能。

在下划线约定中有一种私有变量的变体。

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

有一些细微的区别,但是为了编程模式意识形态的纯洁性,它已经足够好了。

有一些@private decorator的例子更紧密地实现了这个概念,但你的情况可能会有所不同。可以说,也可以编写使用meta的类定义。