问题:Python在类中是否具有“私有”变量?

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

在阅读类时,它继续说在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中不需要这样做?

I’m coming from the Java world and reading Bruce Eckels’ Python 3 Patterns, Recipes and Idioms.

While reading about classes, it goes on to say that in Python there is no need to declare instance variables. You just use them in the constructor, and boom, they are there.

So for example:

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())

If that’s true, then any object of class Simple can just change the value of variable s outside of the class.

For example:

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

In Java, we have been taught about public/private/protected variables. Those keywords make sense because at times you want variables in a class to which no one outside the class has access to.

Why is that not required in Python?


回答 0

这是文化的。在Python中,您无需写入其他类的实例或类变量。在Java中,如果您真的想做的话,什么也不能阻止您做同样的事情-毕竟,您始终可以编辑类本身的源代码以达到相同的效果。Python放弃了这种安全性的幌子,并鼓励程序员负责。实际上,这非常好用。

如果出于某种原因要模拟私有变量,则始终可以使用PEP 8中__前缀。Python会像这样对变量名称进行修饰,以使它们在包含它们的类之外的代码中不易被看到(尽管只要有足够的决心,您可以解决它,就像您可以使用它来避开Java保护一样)。__foo

按照相同的约定,即使没有从技术上阻止您这样做_前缀也意味着不要离开。您不会玩弄看起来像__foo或的另一个类的变量_bar

It’s cultural. In Python, you don’t write to other classes’ instance or class variables. In Java, nothing prevents you from doing the same if you really want to – after all, you can always edit the source of the class itself to achieve the same effect. Python drops that pretence of security and encourages programmers to be responsible. In practice, this works very nicely.

If you want to emulate private variables for some reason, you can always use the __ prefix from PEP 8. Python mangles the names of variables like __foo so that they’re not easily visible to code outside the class that contains them (although you can get around it if you’re determined enough, just like you can get around Java’s protections if you work at it).

By the same convention, the _ prefix means stay away even if you’re not technically prevented from doing so. You don’t play around with another class’s variables that look like __foo or _bar.


回答 1

python中的私有变量或多或少是一种技巧:解释器故意重命名该变量。

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()…毕竟,创建函数是为了可重用性,内部的语句没有特殊的功能。

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

Private variables in python is more or less a hack: the interpreter intentionally renames the variable.

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

Now, if you try to access __var outside the class definition, it will fail:

 >>>x = A()
 >>>x.__var # this will return error: "A has no attribute __var"

 >>>x.printVar() # this gives back 123

But you can easily get away with this:

 >>>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

You probably know that methods in OOP are invoked like this: x.printVar() => A.printVar(x), if A.printVar() can access some field in x, this field can also be accessed outside A.printVar()…after all, functions are created for reusability, there is no special power given to the statements inside.

The game is different when there is a compiler involved (privacy is a compiler level concept). It know about class definition with access control modifiers so it can error out if the rules are not being followed at compile time


回答 2

正如上面的许多评论所正确提到的,我们不要忘记访问修饰符的主要目标:帮助代码用户理解应该更改的内容和不应该更改的内容。当您看到一个私有字段时,您不会把它弄乱。因此,主要是语法糖,可以通过_和__在Python中轻松实现。

As correctly mentioned by many of the comments above, let’s not forget the main goal of Access Modifiers: To help users of code understand what is supposed to change and what is supposed not to. When you see a private field you don’t mess around with it. So it’s mostly syntactic sugar which is easily achieved in Python by the _ and __.


回答 3

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

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的类定义

There is a variation of private variables in the underscore convention.

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'

There are some subtle differences, but for the sake of programming pattern ideological purity, its good enough.

There are examples out there of @private decorators that more closely implement the concept, but YMMV. Arguably one could also write a class defintion that uses meta


回答 4

“在Java中,我们被教导有关公共/私有/保护变量”

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

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

您可以自由使用-或不使用privateand protected

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

为什么不?

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

我团队中的其他程序员?他们有出处。受保护的人何时可以更改它意味着什么?

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

客户?(通常)是按需租用的程序。客户(通常)拥有代码。

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

“In java, we have been taught about public/private/protected variables”

“Why is that not required in python?”

For the same reason, it’s not required in Java.

You’re free to use — or not use private and protected.

As a Python and Java programmer, I’ve found that private and protected are very, very important design concepts. But as a practical matter, in tens of thousands of lines of Java and Python, I’ve never actually used private or protected.

Why not?

Here’s my question “protected from whom?”

Other programmers on my team? They have the source. What does protected mean when they can change it?

Other programmers on other teams? They work for the same company. They can — with a phone call — get the source.

Clients? It’s work-for-hire programming (generally). The clients (generally) own the code.

So, who — precisely — am I protecting it from?


回答 5

如前所述,您可以通过在变量或方法前加上下划线作为前缀来表明该变量或方法是私有的。如果您觉得不够,可以随时使用property装饰器。这是一个例子:

class Foo:

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

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

这样,引用的某人或某物bar实际上是在引用bar函数的返回值,而不是变量本身,因此可以访问但不能更改。但是,如果有人真的想要,他们可以简单地使用_bar并为其分配新的值。就像反复提到的那样,没有一种万无一失的方法可以防止某人访问您想要隐藏的变量和方法。但是,使用property可以发送的最清晰的消息是不要编辑变量。property也可以用于更复杂的getter / setter / deleter访问路径,如下所示:https : //docs.python.org/3/library/functions.html#property

As mentioned earlier, you can indicate that a variable or method is private by prefixing it with an underscore. If you don’t feel like this is enough, you can always use the property decorator. Here’s an example:

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


回答 6

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

有关更多信息,请参见此处

通常,与其他语言相比,Python的面向对象的实现有点原始。但实际上,我很喜欢。从概念上讲,这是一种非常简单的实现,非常适合该语言的动态样式。

Python has limited support for private identifiers, through a feature that automatically prepends the class name to any identifiers starting with two underscores. This is transparent to the programmer, for the most part, but the net effect is that any variables named this way can be used as private variables.

See here for more on that.

In general, Python’s implementation of object orientation is a bit primitive compared to other languages. But I enjoy this, actually. It’s a very conceptually simple implementation and fits well with the dynamic style of the language.


回答 7

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

如前所述,这再次涉及文化。我一直在从事免费阅读和编写其他类变量的项目。一个实现被弃用时,识别使用该功能的所有代码路径的时间要长得多。当强制使用setter和getter时,可以很容易地编写一条调试语句来识别已调用了不赞成使用的方法以及调用该方法的代码路径。

当您在任何人都可以编写扩展的项目上时,通知用户有关已弃用的方法的信息,这些方法将在几个发行版中消失,因此对于将升级时模块的损坏降至最低至关重要。

所以我的答案是;如果您和您的同事维护一个简单的代码集,那么保护类变量并非总是必要的。如果您正在编写一个可扩展的系统,那么对内核进行的更改就变得势在必行,而所有的扩展都需要使用代码来捕获这些更改。

The only time I ever use private variables is when I need to do other things when writing to or reading from the variable and as such I need to force the use of a setter and/or getter.

Again this goes to culture, as already stated. I’ve been working on projects where reading and writing other classes variables was free-for-all. When one implementation became deprecated it took a lot longer to identify all code paths that used that function. When use of setters and getters was forced, a debug statement could easily be written to identify that the deprecated method had been called and the code path that calls it.

When you are on a project where anyone can write an extension, notifying users about deprecated methods that are to disappear in a few releases hence is vital to keep module breakage at a minimum upon upgrades.

So my answer is; if you and your colleagues maintain a simple code set then protecting class variables is not always necessary. If you are writing an extensible system then it becomes imperative when changes to the core is made that needs to be caught by all extensions using the code.


回答 8

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

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

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

private and protected concepts are very important. But python – just a tool for prototyping and rapid development with restricted resources available for development, that is why some of protection levels are not so strict followed in python. You can use “__” in class member, it works properly, but looks not good enough – each access to such field contains these characters.

Also, you can noticed that python OOP concept is not perfect, smaltalk or ruby much closer to pure OOP concept. Even C# or Java are closer.

Python is very good tool. But it is simplified OOP language. Syntactically and conceptually simplified. The main goal of python existence is to bring to developers possibility to write easy readable code with high abstraction level in a very fast manner.


回答 9

抱歉,“恢复”线程,但是,我希望这会对某人有所帮助:

在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中一样,将其变为“私有”属性。该属性的名称仍然是全局的,但是以一种无法访问的方式,就像其他语言中的私有属性一样。

但是不要害怕。没关系 它也做这项工作。;)

Sorry guys for “resurrecting” the thread, but, I hope this will help someone:

In Python3 if you just want to “encapsulate” the class attributes, like in Java, you can just do the same thing like this:

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())

To instantiate this do:

ss = Simple("lol")
ss.show()

Note that: print(ss.__s) will throw an error.

In practice, Python3 will obfuscate the global attribute name. Turning this like a “private” attribute, like in Java. The attribute’s name is still global, but in an inaccessible way, like a private attribute in other languages.

But don’t be afraid of it. It doesn’t matter. It does the job too. ;)


回答 10

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

self .__ foobar的名称会在A类中自动更改为self._A__foobar。在B类中,其名称将更改为self._B__foobar。因此,每个子类都可以定义自己的变量__foobar而不覆盖其父变量。但是没有什么可以阻止您访问以双下划线开头的变量。但是,名称修改可防止您偶然调用此变量/方法。

我强烈建议观看Raymond Hettingers谈论Pycon 2013上的“ Pythons类开发工具包”(应该在Youtube上提供),该示例很好地说明了为什么以及如何使用@property和“ __”-instance变量。

Python does not have any private variables like C++ or Java does. You could access any member variable at any time if wanted, too. However, you don’t need private variables in Python, because in Python it is not bad to expose your classes member variables. If you have the need to encapsulate a member variable, you can do this by using “@property” later on without breaking existing client code.

In python the single underscore “_” is used to indicate, that a method or variable is not considered as part of the public api of a class and that this part of the api could change between different versions. You can use these methods/variables, but your code could break, if you use a newer version of this class.

The double underscore “__” does not mean a “private variable”. You use it to define variables which are “class local” and which can not be easily overidden by subclasses. It mangles the variables name.

For example:

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.__foobar’s name is automatically mangled to self._A__foobar in class A. In class B it is mangled to self._B__foobar. So every subclass can define its own variable __foobar without overriding its parents variable(s). But nothing prevents you from accessing variables beginning with double underscores. However, name-mangling prevents you from calling this variables /methods incidentally.

I strongly recommend to watch Raymond Hettingers talk “Pythons class development toolkit” from Pycon 2013 (should be available on Youtube), which gives a good example why and how you should use @property and “__”-instance variables.


回答 11

实际上,您可以C#使用以下简单技巧来模拟吸气剂和吸气剂:

class Screen(object):

    def getter_setter_y(self, y, get=True):
        if get is True:
            Screen.getter_setter_y.value = y
        else:
            return Screen.getter_setter_y.value

     def getter_setter_x(self, x, get=True):
         if get is True:
             Screen.getter_setter_x.value = x
         else:
             return Screen.getter_setter_x.value

然后像这样使用它C#

scr = Screen()
scr.getter_setter_x(100)
value =  scr.getter_setter_x(0, get=False)
print (value)

这只是在函数中声明一个静态局部变量,该变量将扮演获取/设置的角色,因为这是通过get和set方法共享变量的唯一方法,而无需将其全局化为类或文件。

Actually you can simulate a C# getter and setter using this simple trick:

class Screen(object):

    def getter_setter_y(self, y, get=True):
        if get is True:
            Screen.getter_setter_y.value = y
        else:
            return Screen.getter_setter_y.value

     def getter_setter_x(self, x, get=True):
         if get is True:
             Screen.getter_setter_x.value = x
         else:
             return Screen.getter_setter_x.value

Then use it similar like in C#:

scr = Screen()
scr.getter_setter_x(100)
value =  scr.getter_setter_x(0, get=False)
print (value)

It’s just declaring a static local variable in a function that will play a get/set role, since that’s the only way to share a variable via get and set methods, without make it global for a class or file.


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。