我来自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中不需要这个?


当前回答

在Python 3中,如果你只是想“封装”类属性,就像在Java中一样,你可以这样做:

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

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

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

要实例化此操作:

ss = Simple("lol")
ss.show()

注意:print(ss.__s)将抛出一个错误。

实际上,Python 3会混淆全局属性名。就像在Java中一样,它将此转换为“私有”属性。属性名仍然是全局的,但是以一种不可访问的方式,就像其他语言中的私有属性一样。

但是不要害怕。没关系。它也起作用了。;)

其他回答

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

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

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

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

Python对私有标识符的支持有限,通过一个自动在任何以两个下划线开头的标识符前加上类名的特性。在大多数情况下,这对程序员来说是透明的,但最终结果是任何以这种方式命名的变量都可以用作私有变量。

更多信息请参见这里。

一般来说,与其他语言相比,Python的面向对象实现有点原始。但实际上我很享受这个过程。这是一个概念上非常简单的实现,非常适合该语言的动态风格。

如前所述,可以通过在变量或方法前面加上下划线来表示它是私有的。如果您觉得这还不够,还可以使用属性装饰器。这里有一个例子:

class Foo:

    def __init__(self, bar):
        self._bar = bar

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

This way, someone or something that references bar is actually referencing the return value of the bar function rather than the variable itself, and therefore it can be accessed but not changed. However, if someone really wanted to, they could simply use _bar and assign a new value to it. There is no surefire way to prevent someone from accessing variables and methods that you wish to hide, as has been said repeatedly. However, using property is the clearest message you can send that a variable is not to be edited. property can also be used for more complex getter/setter/deleter access paths, as explained here: https://docs.python.org/3/library/functions.html#property

下面是我处理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.

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

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的类定义。