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放弃了安全性的伪装,鼓励程序员负责任。实际上,这非常有效

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

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

“在java中,我们学习了公共/私有/保护变量”

“为什么python中不需要这样做?”

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

您可以自由使用或不使用
private
protected

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

为什么不呢

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

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

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

客户?这是雇佣编程的工作(通常)。客户机(通常)拥有代码


那么,我到底是在保护谁呢?

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

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


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

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

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

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


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

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

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'
[5]中的
:类测试(对象):
…:def_uuprivate_方法(self):
…:返回“Boo”
…:def public_方法(self):
…:返回self.\u private\u方法()
...:     
在[6]中:x=Test()
[7]中:x.公共_方法()
Out[7]:“Boo”
在[8]中:x.\u private\u method()
---------------------------------------------------------------------------
AttributeError回溯(最近一次呼叫上次)
在()
---->1 x.私有方法()
AttributeError:“Test”对象没有属性“\uu private\u method”
Ther
>>> 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
class Foo:

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

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