Python在类中有“私有”variables吗?

我来自Java世界,阅读Bruce Eckels的Python 3 Patterns,Recipes和Idioms

在阅读类时,它继续说在Python中不需要声明实例variables。 你只是在构造函数中使用它们,繁荣,它们在那里。

举个例子:

class Simple: def __init__(self1, str): print("inside the simple constructor") self1.s = str def show(self1): print(self1.s) def showMsg (self, msg): print (msg + ':', self.show()) 

如果这是真的,那么Simple类的任何对象都可以在类之外改变variabless值。

例如:

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

在Java中,我们被教授关于公共/私有/受保护的variables。 这些关键字是有意义的,因为有时候你想要一个class级以外的class级无法访问的variables。

为什么在Python中不需要?

这是文化。 在Python中,您不会写入其他类的实例或类variables。 在Java中,如果你真的想要做什么,就不会有什么妨碍 – 毕竟,你总是可以编辑类本身的源码来达到同样的效果。 Python放弃了安全的伪装,并鼓励程序员负责。 在实践中,这很好地工作。

如果你想出于某种原因模拟私有variables,你总是可以使用PEP 8中的__前缀。 Python会像__foo一样__foovariables的名称,以便在包含它们的类之外进行编码时不容易看到它们(尽pipe如果您足够坚决, 可以绕过它,就像您可以绕过Java的保护一样它)。

按照同样的惯例, 即使你在技术上没有被阻止_前缀意味着远离 。 你不玩弄另外一个类似于__foo_bar的variables。

Python中的私有variables或多或less是一种破解:解释器故意重命名variables。

 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() …毕竟,函数是为了可重用性而创build的,没有特别的权力赋予里面的语句。

涉及编译器时,游戏是不同的( 隐私是编译器级别的概念 )。 它使用访问控制修饰符知道类的定义,所以如果在编译时没有遵循这些规则,就会出错

“在Java中,我们已经被教授关于公共/私有/受保护的variables”

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

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

你可以自由使用 – 或不使用privateprotected

作为Python和Java程序员,我发现privateprotected是非常非常重要的devise概念。 但实际上,在数万行的Java和Python中,我从来没有真正使用privateprotected

为什么不?

这是我的问题“保护谁?”

其他程序员在我的团队? 他们有源。 保护是什么意思,当他们可以改变它?

其他程序员在其他团队? 他们为同一家公司工作。 他们可以 – 通过电话 – 获取来源。

客户端? 这是雇用的编程(通常)。 客户(通常)拥有代码。

那么,究竟是谁呢,我保护它呢?

对。 拒绝阅读API评论的精神分裂反社会人士。

正如上面的许多评论所正确提到的那样,我们不要忘记访问修饰符的主要目标:帮助代码用户理解应该改变什么以及不应该改变什么。 当你看到一个私人领域,你不会乱它。 所以它主要是Python和_和__很容易实现的语法糖。

Python对私有标识符的支持有限,它通过一个自动将类名前缀到任何以两个下划线开始的标识符的特性。 这对程序员来说是透明的,但最终结果是,任何以这种方式命名的variables都可以用作私有variables。

在这里看到更多的。

一般来说,与其他语言相比,Python的面向对象的实现有点原始。 但我真的很喜欢这个 这是一个非常简单的实现,非常适合语言的dynamic风格。

私人和受保护的概念是非常重要的。 但是python只是一个原型和快速开发的工具,可用于开发的资源有限,这就是为什么一些保护级别在python中没有被严格遵循的原因。 您可以在类成员中使用“__”,它可以正常工作,但看起来不够好 – 每个对这个字段的访问都包含这些字符。

另外,你可以注意到python OOP的概念并不完美,更接近纯粹的OOP概念。 即使C#或Java更接近。

Python是非常好的工具。 但它是简化的OOP语言。 从句法和概念上简化。 python存在的主要目标是为开发人员提供以非常快速的方式编写高抽象级别易读代码的可能性。

我唯一使用私有variables的时候是当我写variables或从variables读取时需要做其他事情,因此我需要强制使用setter和/或getter。

如前所述,这也是文化的一部分。 我一直在做项目,读和写其他类variables是免费的。 当一个实现被弃用时,识别所有使用该函数的代码path需要花费更长的时间。 当强制使用setter和getter时,可以很容易地编写debugging语句来确定已经调用了不赞成使用的方法,并调用它的代码path。

当您在任何人都可以编写扩展的项目上时,通知用户有关在几个版本中消失的已弃用方法,因此在升级时至less要保持模块损坏至关重要。

所以我的答案是 如果你和你的同事维护一个简单的代码集,那么保护类variables并不总是必要的。 如果你正在编写一个可扩展的系统,那么当核心发生变化时,所有扩展都需要使用代码来捕获这些变化。

下划线约定中的私有variables有一些变化。

 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装饰器的例子更接近实现这个概念,但YMMV。 可以说,也可以写一个使用meta的类定义

如前所述,您可以通过在下划线前加一个前缀来表示一个variables或方法是私有的。 如果你觉得这样做不够用,你可以随时使用property装饰器。 这是一个例子:

  class Foo: def __init__(self, bar): self._bar = bar @property def bar(self): """Getter for '_bar'.""" return self._bar 

这样,引用bar人或事物实际上引用了bar函数的返回值而不是variables本身,因此可以访问但不能更改。 但是,如果有人真的想,他们可以简单地使用_bar并为其分配一个新的值。 反复地说,没有办法阻止某人访问你想隐藏的variables和方法。 但是,使用property是您可以发送的最清晰的消息,即不要编辑variables。 property也可以用于更复杂的getter / setter / deleter访问path,如下所述: https : //docs.python.org/3/library/functions.html#property

对不起,“复苏”的男士们,但是,我希望这可以帮助别人:

在Python3中,如果你只想“封装”类属性,就像在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)将会出现错误。

在实践中,Python3将模仿全局属性名称。 把它变成一个“私有”属性,就像在Java中一样。 属性名称仍然是全局的,但以不可接受的方式,如其他语言中的私有属性。

但是不要害怕这个。 它非常重要。 它也做这个工作。 ;)