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


当前回答

关于源代码(更改访问权限,从而绕过Java或c++等语言封装):

您并不总是拥有源代码,即使您拥有源代码,这些源代码也由一个只允许特定程序员访问源代码的系统管理(在专业上下文中)。通常,每个程序员都负责某些类,因此知道自己能做什么,不能做什么。源代码管理器还锁定正在修改的源代码,当然,还管理程序员的访问权限。

所以根据经验,我更相信软件而不是人。所以约定很好,但多重保护更好,比如访问管理(真正的私有变量)+源代码管理。

其他回答

私有变量在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()之外访问…毕竟,函数是为可重用性而创建的,其中的语句并没有任何特殊的功能。

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

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.

Python不像c++或Java那样有任何私有变量。如果需要,还可以在任何时候访问任何成员变量。然而,在Python中不需要私有变量,因为在Python中公开类的成员变量并不坏。如果需要封装成员变量,可以稍后使用“@property”来实现,而不会破坏现有的客户端代码。

在Python中,单个下划线“_”用于表示方法或变量不被视为类的公共API的一部分,并且API的这一部分可以在不同版本之间更改。您可以使用这些方法和变量,但是如果您使用这个类的新版本,您的代码可能会中断。

双下划线“__”并不意味着“私有变量”。你可以使用它来定义“类本地”变量,这些变量不容易被子类覆盖。它破坏了变量名。

例如:

class A(object):
    def __init__(self):
        self.__foobar = None # Will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # Will be automatically mangled to self._B__foobar

自我。__foobar的名称自动被破坏为self。在类B中,它被破坏为self._B__foobar。因此,每个子类都可以定义自己的变量__foobar,而不重写其父变量。但是没有什么可以阻止您访问以双下划线开头的变量。但是,name mangling阻止你偶然调用这些变量/方法。

我强烈建议你观看Raymond Hettinger的Python类开发工具包,它提供了一个很好的例子,为什么以及如何使用@property和“__”-实例变量。

如果您已经公开了公共变量,并且需要封装它们,那么可以使用@property。因此,您可以从最简单的解决方案开始。你可以让成员变量为public,除非你有具体的理由不这样做。这里有一个例子:

class Distance:
    def __init__(self, meter):
        self.meter = meter


d = Distance(1.0)
print(d.meter)
# prints 1.0

class Distance:
    def __init__(self, meter):
        # Customer request: Distances must be stored in millimeters.
        # Public available internals must be changed.
        # This would break client code in C++.
        # This is why you never expose public variables in C++ or Java.
        # However, this is Python.
        self.millimeter = meter * 1000

    # In Python we have @property to the rescue.
    @property
    def meter(self):
        return self.millimeter *0.001

    @meter.setter
    def meter(self, value):
        self.millimeter = value * 1000

d = Distance(1.0)
print(d.meter)
# prints 1.0

正如上面许多评论所正确提到的,让我们不要忘记Access Modifiers的主要目标:帮助代码的用户理解应该改变什么,不应该改变什么。当你看到一个私有的字段时,你不要乱摆弄它。所以它主要是语法糖,这在Python中很容易通过_和__实现。