我来自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中或多或少是一种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()之外访问…毕竟,函数是为可重用性而创建的,其中的语句并没有任何特殊的功能。

其他回答

在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中一样,它将此转换为“私有”属性。属性名仍然是全局的,但是以一种不可访问的方式,就像其他语言中的私有属性一样。

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

我是Python的新手但我有c#和JavaScript的背景。就特性而言,Python感觉像是两者的混合体。JavaScript在这方面也有问题,解决方法是创建一个闭包。这可以通过返回不同的对象来防止访问您不想公开的数据。

def print_msg(msg):
    # This is the outer enclosing function

    def printer():
        # This is the nested function
        print(msg)

    return printer  # returns the nested function


# Now let's try calling this function.
# Output: Hello
another = print_msg("Hello")
another()

https://www.programiz.com/python-programming/closure

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#emulating_private_methods_with_closures

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

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

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

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

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

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

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

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

更多信息请参见这里。

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