Python类中是否有“私有”变量?

Python类中是否有“私有”变量?,python,class,private,Python,Class,Private,我来自Java世界,阅读Bruce Eckels的Python 3模式、食谱和习惯用法 在阅读有关类的内容时,它接着说在Python中不需要声明实例变量。你只要在构造器中使用它们,它们就在那里 例如: class Simple: def __init__(self, s): print("inside the simple constructor") self.s = s def show(self): print(self.s)

我来自Java世界,阅读Bruce Eckels的Python 3模式、食谱和习惯用法

在阅读有关类的内容时,它接着说在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())
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
如果这是真的,那么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对私有标识符的支持有限,因为它的一个特性是自动将类名前置到任何以两个下划线开头的标识符。这在很大程度上对程序员来说是透明的,但最终的效果是,任何以这种方式命名的变量都可以用作私有变量

更多信息请参见


一般来说,与其他语言相比,Python的面向对象实现有点原始。但事实上,我喜欢这样。这是一个概念上非常简单的实现,非常符合语言的动态风格。

这是一种文化。在Python中,您不会写入其他类的实例或类变量。在Java中,如果您真的想这样做,没有什么可以阻止您这样做——毕竟,您可以随时编辑类本身的源代码以达到相同的效果。Python放弃了安全性的伪装,鼓励程序员负责任。实际上,这非常有效

如果出于某种原因希望模拟私有变量,则始终可以使用来自的_u_uu前缀。Python会破坏变量的名称,比如_foo,这样它们就不容易被包含它们的类之外的代码看到,尽管如果你有足够的决心,你可以绕过它,就像你可以绕过Java的保护一样


按照同样的惯例,u前缀意味着远离,即使在技术上你没有被阻止这样做。您不能随意使用另一个类的变量,这些变量看起来像uuufoo或bar。

在java中,我们已经学到了关于公共/私有/保护变量的知识

为什么python中不需要这样做

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

您可以自由使用-也可以不使用私人和受保护的

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

为什么不呢

这是我的问题,保护谁

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

其他团队的其他程序员?他们在同一家公司工作。他们可以通过打电话得到消息来源

客户?一般来说,这是雇佣编程的工作。客户机通常拥有代码


所以,我到底是在保护谁?

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

另外,您可以注意到python OOP概念并不完美,smaltalk或ruby更接近纯OOP概念。甚至C和Java都更接近


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

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

如前所述,这同样涉及到文化。我一直在从事一些项目,在这些项目中,所有人都可以免费阅读和编写其他类变量。当一个实现被弃用时,识别使用该函数的所有代码路径需要花费更长的时间。当强制使用setter和getter时,可以很容易地编写一条debug语句来标识已调用不推荐的方法以及调用该方法的代码路径

当您在一个任何人都可以编写扩展的项目中时,通知用户一些不推荐的方法将在几个版本中消失,因此在升级时将模块损坏保持在最低限度是至关重要的

所以我的答案是,;如果您和您的同事维护一个简单的代码集,那么保护类变量并不总是必要的。如果你是wri
当所有使用代码的扩展都需要捕获对核心所做的更改时,对可扩展系统进行修改就变得非常必要

下划线约定中存在私有变量的变化

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 decorators的例子可以更紧密地实现这个概念,但是YMMV。可以说,我们也可以编写一个使用meta的类定义,正如上面许多评论所正确提到的,让我们不要忘记访问修饰符的主要目标:帮助代码用户理解什么应该更改,什么不应该更改。当你看到一个私人领域时,你不会乱来。因此,在Python中,主要是通过u和u u u u u u u u u u u

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.printVarx,如果A.printVar可以访问x中的某个字段,那么该字段也可以在A.printVar外部访问……毕竟,函数是为可重用性而创建的,内部的语句没有特殊的功能


当有编译器参与时,游戏就不同了。隐私是编译器级别的概念。它知道带有访问控制修饰符的类定义,因此如果在编译时没有遵循规则,它可能会出错。

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

class Foo:

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

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar
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 = meter * 1000

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

这样,引用bar的某人或某物实际上引用的是bar函数的返回值,而不是变量本身,因此它可以访问但不能更改。然而,如果有人真的想这样做,他们可以简单地使用_-bar并为其指定一个新值。正如反复提到的那样,没有可靠的方法可以阻止某人访问您希望隐藏的变量和方法。但是,使用属性是您可以发送的最清楚的消息,即不可编辑变量。属性还可以用于更复杂的getter/setter/deleter访问路径,如下所述:

很抱歉,伙计们恢复了线程,但是,我希望这能帮助一些人:

在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()
请注意:printss.\u将抛出一个错误

实际上,Python3会混淆全局属性名。将其转换为私有属性,就像在Java中一样。该属性的名称仍然是全局的,但与其他语言中的私有属性一样,是无法访问的


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

Python没有任何私有变量,如C++或java。如果需要,您也可以随时访问任何成员变量。但是,在Python中不需要私有变量,因为在Python中公开类成员变量并不坏。如果需要封装成员变量,可以稍后使用@property,而不破坏现有的客户端代码

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

双下划线并不表示私有变量。您可以使用它来定义变量,这些变量是类本地的,并且不容易被子类覆盖。它会破坏变量名

例如:

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())
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
self.\u foobar的名称会自动更改为self.\u A\u foobar在类A中。在类B中它会更改为self.\u B\u foobar。因此,每个子类都可以定义自己的变量\uuufoobar,而无需覆盖其父变量。但是没有什么可以阻止您访问以双下划线开头的变量。但是,名称混乱会阻止您意外调用此变量/方法

我强烈建议观看Raymond Hettingers讲述的Pycon 2013中的Pythons类开发工具包应该在Youtube上提供,它给出了一个很好的示例,说明了为什么以及如何使用@property和_;-instance变量

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

class Foo:

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

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar
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 = meter * 1000

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

关于更改访问权的来源,因此bypa ss语言封装,如java或C++: 您并不总是拥有源代码,即使您拥有,源代码也由一个系统管理,该系统只允许某些程序员在专业环境中访问源代码。通常,每个程序员都负责某些类,因此知道自己能做什么和不能做什么。源代码管理器还锁定正在修改的源代码,当然,还管理程序员的访问权限


因此,根据经验,我更信任软件而不是人。所以约定是好的,但多重保护更好,比如访问管理、真实私有变量+源管理。

这很有意义。然而,我不认为java中有任何方法可以访问类外的私有变量,当然,除了实际更改类的源之外。有吗?我倾向于选择python方式,但我认为java方式并不像你想象的那样毫无意义。声明某个私有属性会很快告诉阅读代码的人一些非常有用的东西:这个字段只在这个类中被修改过。@Omnipresent,你可以使用反射。让我说清楚,Python不实现公共或私有属性,因为这是一种安全伪装,鼓励程序员负责,然而,社区鼓励使用u来表示私有变量和方法?也许python应该明确地具有public和private no?它们的主要目的是告诉您应该使用什么API与类交互。它们作为一个文档,告诉您使用这些方法,而不是使用那些方法。它们不是安全的伪装,它们是API文档,甚至可以被IDE用来指导您!这是一个很好的答案,你的推理当然是正确的,但有一点我不同意。访问修饰符的用途从来都不是安全性。相反,它们是一种明确划分和在很大程度上强制执行类的哪些部分被认为是内部的,哪些部分向该类的外部用户公开的方法。约定区域性当然是访问修饰符的有效替代方法,两种方法都有各自的优缺点,但语言级访问修饰符在任何方面都是安全的,这是一种误导。您指的是实例变量,而不是类变量,对吗?您应该检查属性:。只需使用getter,您的变量就会得到保护。我希望这会有帮助。-1:我同意豪猪。这不是关于禁止访问或隐藏某些内容,而是关于隐式API文档。开发人员和编译器/解释器/代码检查器都可以很容易地看到哪些成员被推荐使用,哪些成员不应该被触碰,或者至少要小心。在大多数情况下,如果一个类或模块的所有成员都是公共的,那将是一个可怕的混乱。考虑私人/受保护/公共成员作为服务的区别,说:嘿,这些成员很重要,而那些在内部使用,可能对你没有用处。但是,Porculus和Oben在这里请求的所有内容都通过前缀it和下划线约定得到了完美的处理,并且没有编译器强制执行该约定可能带来的伤害cause@ncoghlan这些观点在互联网和大量Python出版物中都有发表。并没有让他们成为圣经。编译器执行接口、强大的数据封装和类型化被许多人认为是巨大的好处。隐私无助于将设计封装起来。同意不同意。隐私只是。。。帮助那些不能阅读文档或拒绝遵循文档的人。再说一次,傻瓜。我们都同意,高级松散类型语言和低级强类型语言都有好处。它们都是工具箱里的工具@我不是python的人,所以我不会从这个角度发表评论。然而,作为一名java开发人员,这确实是一个可怕的建议-哇。你完全没有抓住要点,你给出了一个非常糟糕的建议,你侮辱了任何在这一点上与你意见相左的人,但你仍然会因为这个答案而获得徽章和超过1000点的声誉分数。我意识到这已经很晚了,但谷歌在搜索这个问题时会显示这个链接。这并不是全部__类a中的变量x实际上被编译器重写为_a__x,它仍然不是完全私有的,仍然可以访问。当然,如果我看到一个名为_a__x的变量,我不会去碰它。它可能会传染。我会逃走的,没错,这不是真正的私事。但是C++和java等硬执行私有化的原理推理,编译器优化,在Python中并不存在,所以按照惯例,私有是足够好的。Python的惯例通常是,它相信您会在没有监督的情况下表现自己。这是一个新手陷阱,但是你知道,只是要考虑类的设计和使用。简言之,这不是封装
想知道PHP是否与它愚蠢的私有变量有相似之处——因为私有变量在解释语言中没有真正的意义——我的意思是,如果x变量是私有的,如果它没有编译,它能做什么优化?我们如何随机化私有变量的模式?@Criron samequestion@watashiSHUN简言之这不是封装=>是的。封装是关于只使用公共API,以便保护客户端代码不受实现更改的影响。命名约定是判断什么是API、什么是实现的一种非常有效的方法,关键是它可以正常工作。我认为这一点与其他任何一点一样重要。在调试我知道的代码时,我是一个容易引入bug的弱者,知道哪些类可以更改成员变量可以简化调试过程。至少,如果变量受到某个范围的保护。类似的概念是C++中的const函数。我知道其中的成员变量没有更改,所以我甚至不认为该方法是导致变量设置错误的潜在原因。虽然它可以进行类扩展/添加功能的后续开发,但限制代码的可见性会使调试更容易。私有和受保护的关系非常重要,因为在静态编译语言中,编译器可以创建对私有方法的直接调用,但必须依赖公共方法的查找表。这对于动态语言来说根本不是问题。最后,像C++这样的语言对继承和方法解析有影响。Python和Ruby具有非常相似的OO实现,因此比较毫无意义。Smalltalk实际上没有公共/私人消息的概念。您可以自由添加私人作为一个类别,但它纯粹是咨询。进一步我的主张。从编码卫生的角度来看,是的,它们对封装很重要,但不是必需的,因此@private etc decorator比任何东西都更具建议性,但由于private/public在非静态语言中对优化没有任何帮助,它没有像java或CTC这样的编译语言那样在深层次上实现。自Python 1.5.2 IIRC以来,它就已经存在了,而且它仍然不会阻止通过其损坏的名称访问该属性。该属性名称不是全局的。Django也很欣赏这一点。我将看看这篇演讲。@property是标准Python的一部分,还是特定于IDE?自Python 2.6以来,它就是标准的一部分。如果您应该使用较旧的版本,那么仍然可以使用属性内置函数,该函数自python 2.2Yep以来就可用。其美妙之处在于,python的元编程能力意味着您可以根据自己的需要实际实现这些奇特的东西,并且有一些库可以实现@private/@protected/etc装饰器等。见鬼,我甚至看到一个库,它实现了JS风格的原型类,但实际上并没有必要。。我有点讨厌python/js/whatever是一个lisp模因,因为它几乎从来都不是真的,但是python确实与该语言共享“结合了简单语法的元编程技巧”