问题:Python名称修饰

在其他语言中,有助于产生更好代码的通用准则总是使所有内容都尽可能隐藏。如果不确定变量是私有变量还是受保护变量,最好使用私有变量。

同样适用于Python吗?我是否应该首先在所有内容上使用两个前导下划线,并且仅在需要时才使它们的隐藏性降低(仅一个下划线)?

如果约定只使用一个下划线,我也想知道其基本原理。

这是我对JBernardo的回答所留下的评论。它解释了为什么我问这个问题,以及为什么我想知道为什么Python与其他语言不同的原因:

我来自可以训练您的语言,使您认为一切都应该仅在需要时公开,而不能再公开了。原因是这将减少依赖关系并使代码更安全地更改。Python反向做事的方式-从公开开始到隐蔽-对我来说很奇怪。

In other languages, a general guideline that helps produce better code is always make everything as hidden as possible. If in doubt about whether a variable should be private or protected, it’s better to go with private.

Does the same hold true for Python? Should I use two leading underscores on everything at first, and only make them less hidden (only one underscore) as I need them?

If the convention is to use only one underscore, I’d also like to know the rationale.

Here’s a comment I left on JBernardo’s answer. It explains why I asked this question and also why I’d like to know why Python is different from the other languages:

I come from languages that train you to think everything should be only as public as needed and no more. The reasoning is that this will reduce dependencies and make the code safer to alter. The Python way of doing things in reverse — starting from public and going towards hidden — is odd to me.


回答 0

如有疑问,请将其保留为“公开”-我的意思是,请勿添加任何内容以掩盖您的属性名称。如果您的类具有一些内部值,请不要理会。而不是写:

class Stack(object):

    def __init__(self):
        self.__storage = [] # Too uptight

    def push(self, value):
        self.__storage.append(value)

默认写这个:

class Stack(object):

    def __init__(self):
        self.storage = [] # No mangling

    def push(self, value):
        self.storage.append(value)

这无疑是一种有争议的做事方式。Python的新手只是讨厌它,甚至一些老的Python人士都鄙视了此默认设置-但这仍然是默认设置,因此即使您感到不舒服,我也建议您遵循它。

如果您确实要发送消息“无法触摸此!” 对于您的用户,通常的方法是在变量前加一个下划线。这只是一个约定,但是人们理解它并且在处理这些东西时要格外小心:

class Stack(object):

    def __init__(self):
        self._storage = [] # This is ok but pythonistas use it to be relaxed about it

    def push(self, value):
        self._storage.append(value)

这对于避免属性名称和属性名称之间的冲突也很有用:

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0

     @property
     def age(self):
         return self._age

     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

那双下划线呢?好吧,双下划线魔术主要用于避免方法的意外重载和名称与超类的属性的冲突。。如果您编写一个预期会扩展很多次的类,这将非常有用。

如果您想将其用于其他目的,可以,但是既不推荐也不推荐使用。

编辑:为什么会这样?好吧,通常的Python风格并不强调将事情变成私有的-相反!造成这种情况的原因很多-大多数都引起争议…让我们看看其中的一些原因。

Python具有属性

如今,大多数OO语言都采用相反的方法:不应该使用的内容不应该可见,因此属性应该是私有的。从理论上讲,这将产生更易于管理,耦合更少的类,因为没有人会不顾一切地更改对象内部的值。

但是,它并不是那么简单。例如,Java类确实有很多的属性 getter方法,只是得到的值刚刚制定者设定的值。让我们说,您需要七行代码来声明一个属性-Python程序员会说这不必要地复杂。另外,实际上,您只需编写全部代码即可获得一个公共字段,因为您可以使用getter和setter更改其值。

那么,为什么要遵循这种默认的私有策略?默认情况下只需公开您的属性即可。当然,这在Java中是有问题的,因为如果您决定向属性添加一些验证,那么它将要求您更改所有

person.age = age;

在您的代码中,让我们说,

person.setAge(age);

setAge() 存在:

public void setAge(int age) {
    if (age >= 0) {
        this.age = age;
    } else {
        this.age = 0;
    }
}

因此,在Java(和其他语言)中,默认设置是无论如何都使用getter和setter,因为它们可能很烦人,但是如果您遇到我所描述的情况,可以节省很多时间。

但是,由于Python具有属性,因此您不需要在Python中执行此操作。如果您有此类:

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self.age = age

然后您决定验证年龄,则无需更改person.age = age代码段。只需添加一个属性(如下所示)

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0

     @property
     def age(self):
         return self._age

     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

如果您可以做到并且仍然使用 person.age = age,为什么还要添加私有字段以及getter和setter?

(此外,请参阅Python并非Java本文将介绍使用getter和setter的危害。)

一切都是可见的-试图隐藏只会使您的工作复杂化

即使在具有私有属性的语言中,您也可以通过某种反射/自省库来访问它们。人们在框架和解决紧急需求方面做了大量工作。问题在于,自省库只是完成公共属性所能做的一种困难的方法。

由于Python是一种非常动态的语言,因此将负担加到类中只会适得其反。

无法看到问题-这是必需的看到

对于Pythonista,封装不是无法看到类的内部,而是避免查看它的可能性。我的意思是说,封装是组件的属性,它使用户无需担心内部细节即可使用它。如果您可以使用某个组件而不必担心自己的实现,那么它将被封装(Python程序员认为)。

现在,如果您以这样的方式编写类,就可以使用它而不必考虑实现细节,那么出于某种原因想要查看类内部就没有问题。关键是:您的API应该不错,其余的就是细节。

圭多这样说

好吧,这没有争议:实际上他是这么说的。(寻找“开放和服”。)

这是文化

是的,有一些原因,但没有关键原因。这主要是Python编程的文化方面。坦白说,也可能是另一种方式,但事实并非如此。同样,您也可以轻松地反过来问:为什么某些语言默认使用私有属性?出于与Python实践相同的主要原因:因为这是这些语言的文化,每种选择都有其优点和缺点。

由于已经存在这种文化,因此建议您遵循它。否则,__当您在Stack Overflow中提问时,Python程序员会告诉您将其从代码中删除,这会使您感到烦恼:)

When in doubt, leave it “public” – I mean, do not add anything to obscure the name of your attribute. If you have a class with some internal value, do not bother about it. Instead of writing:

class Stack(object):

    def __init__(self):
        self.__storage = [] # Too uptight

    def push(self, value):
        self.__storage.append(value)

write this by default:

class Stack(object):

    def __init__(self):
        self.storage = [] # No mangling

    def push(self, value):
        self.storage.append(value)

This is for sure a controversial way of doing things. Python newbies just hate it and even some old Python guys despise this default – but it is the default anyway, so I really recommend you to follow it, even if you feel uncomfortable.

If you really want to send the message “Can’t touch this!” to your users, the usual way is to precede the variable with one underscore. This is just a convention, but people understand it and take double care when dealing with such stuff:

class Stack(object):

    def __init__(self):
        self._storage = [] # This is ok but pythonistas use it to be relaxed about it

    def push(self, value):
        self._storage.append(value)

This can be useful, too, for avoiding conflict between property names and attribute names:

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0

     @property
     def age(self):
         return self._age

     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

What about the double underscore? Well, the double underscore magic is used mainly to avoid accidental overloading of methods and name conflicts with superclasses’ attributes. It can be quite useful if you write a class that is expected to be extended many times.

If you want to use it for other purposes, you can, but it is neither usual nor recommended.

EDIT: Why is this so? Well, the usual Python style does not emphasize making things private – on the contrary! There are a lot of reasons for that – most of them controversial… Let us see some of them.

Python has properties

Most OO languages today use the opposite approach: what should not be used should not be visible, so attributes should be private. Theoretically, this would yield more manageable, less coupled classes, because no one would change values inside the objects recklessly.

However, it is not so simple. For example, Java classes do have a lot attributes and getters that just get the values and setters that just set the values. You need, let us say, seven lines of code to declare a single attribute – which a Python programmer would say is needlessly complex. Also, in practice, you just write this whole lot of code to get one public field, since you can change its value using the getters and setters.

So why to follow this private-by-default policy? Just make your attributes public by default. Of course, this is problematic in Java, because if you decide to add some validation to your attribute, it would require you to change all

person.age = age;

in your code to, let us say,

person.setAge(age);

setAge() being:

public void setAge(int age) {
    if (age >= 0) {
        this.age = age;
    } else {
        this.age = 0;
    }
}

So in Java (and other languages), the default is to use getters and setters anyway, because they can be annoying to write but can spare you a lot of time if you find yourself in the situation I’ve described.

However, you do not need to do it in Python, since Python has properties. If you have this class:

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self.age = age

and then you decide to validate ages, you do not need to change the person.age = age pieces of your code. Just add a property (as shown below)

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0

     @property
     def age(self):
         return self._age

     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

If you can do it and still use person.age = age, why would you add private fields and getters and setters?

(Also, see Python is not Java and this article about the harms of using getters and setters.).

Everything is visible anyway – and trying to hide just complicates your work

Even in languages where there are private attributes, you can access them through some kind of reflection/introspection library. And people do it a lot, in frameworks and for solving urgent needs. The problem is that introspection libraries are just a hard way of doing what you could do with public attributes.

Since Python is a very dynamic language, it is just counterproductive to add this burden to your classes.

The problem is not being possible to see – it is being required to see

For a Pythonista, encapsulation is not the inability of seeing the internals of classes, but the possibility of avoiding looking at it. What I mean is, encapsulation is the property of a component which allows it to be used without the user being concerned about the internal details. If you can use a component without bothering yourself about its implementation, then it is encapsulated (in the opinion of a Python programmer).

Now, if you wrote your class in such a way you can use it without having to think about implementation details, there is no problem if you want to look inside the class for some reason. The point is: your API should be good and the rest is details.

Guido said so

Well, this is not controversial: he said so, actually. (Look for “open kimono.”)

This is culture

Yes, there are some reasons, but no critical reason. This is mostly a cultural aspect of programming in Python. Frankly, it could be the other way, too – but it is not. Also, you could just as easily ask the other way around: why do some languages use private attributes by default? For the same main reason as for the Python practice: because it is the culture of these languages, and each choice has advantages and disadvantages.

Since there already is this culture, you are well advised to follow it. Otherwise, you will get annoyed by Python programmers telling you to remove the __ from your code when you ask a question in Stack Overflow :)


回答 1

首先-什么是名称修改?

当您在类定义中并使用__any_name或时__any_name_(即两个(或多个)前导下划线和最多一个尾随下划线),将调用名称修饰。

class Demo:
    __any_name = "__any_name"
    __any_other_name_ = "__any_other_name_"

现在:

>>> [n for n in dir(Demo) if 'any' in n]
['_Demo__any_name', '_Demo__any_other_name_']
>>> Demo._Demo__any_name
'__any_name'
>>> Demo._Demo__any_other_name_
'__any_other_name_'

如有疑问,该怎么办?

表面上的用途是防止子类使用类使用的属性。

一个潜在的价值是避免与想要重写行为的子类产生名称冲突,以使父类功能保持按预期运行。但是,Python文档中的示例不能替代Liskov,并且在我发现此有用的地方都没有想到的示例。

缺点是它增加了阅读和理解代码库的认知负担,尤其是在调试时,您在源中看到双下划线名称,而在调试器中看到错误的名称。

我个人的方法是有意避免它。我在非常大的代码库上工作。它的罕见用法像拇指酸痛一样伸出来,似乎没有道理。

您确实需要意识到它,以便在看到它时就知道它。

PEP 8

PEP 8(Python标准库样式指南)目前说(删节):

关于使用的方法存在一些争议 __names

如果您的类打算被子类化,并且您具有不希望使用子类的属性,请考虑使用双引号和下划线来命名它们。

  1. 请注意,整齐的名称中仅使用了简单的类名,因此,如果子类同时选择了相同的类名和属性名,则仍然会发生名称冲突。

  2. 名称修饰可以使某些用途(如调试和__getattr__())变得不太方便。但是,名称修饰算法已被详细记录,并且易于手动执行。

  3. 并非每个人都喜欢名字修饰。尝试在避免意外名称冲突与高级调用方法潜在使用之间进行权衡。

它是如何工作的?

如果在类定义中添加两个下划线(不带双下划线),则该名称将被修饰,并且该对象后将带有下划线和类名:

>>> class Foo(object):
...     __foobar = None
...     _foobaz = None
...     __fooquux__ = None
... 
>>> [name for name in dir(Foo) if 'foo' in name]
['_Foo__foobar', '__fooquux__', '_foobaz']

请注意,只有在解析类定义时,名称才会被篡改:

>>> Foo.__test = None
>>> Foo.__test
>>> Foo._Foo__test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute '_Foo__test'

另外,Python的新手有时在无法手动访问在类定义中看到的名称时,难以理解发生了什么。这不是反对它的有力理由,但是如果您有一个学习的听众,这是要考虑的事情。

一个下划线?

如果约定只使用一个下划线,我也想知道其基本原理。

当我打算让用户不要使用某个属性时,我倾向于只使用一个下划线,但这是因为在我的思维模型中,子类可以访问该名称(他们一直拥有该名称,因为他们可以轻松地找到该名称)。无论如何,名称都乱码)。

如果我正在审查使用该__前缀的代码,我会问为什么他们要进行名称修饰,并且如果使用单个下划线不能做到那么好,请记住,如果子类为该类选择相同的名称,并且尽管如此,class属性还是会发生名称冲突。

First – What is name mangling?

Name mangling is invoked when you are in a class definition and use __any_name or __any_name_, that is, two (or more) leading underscores and at most one trailing underscore.

class Demo:
    __any_name = "__any_name"
    __any_other_name_ = "__any_other_name_"

And now:

>>> [n for n in dir(Demo) if 'any' in n]
['_Demo__any_name', '_Demo__any_other_name_']
>>> Demo._Demo__any_name
'__any_name'
>>> Demo._Demo__any_other_name_
'__any_other_name_'

When in doubt, do what?

The ostensible use is to prevent subclassers from using an attribute that the class uses.

A potential value is in avoiding name collisions with subclassers who want to override behavior, so that the parent class functionality keeps working as expected. However, the example in the Python documentation is not Liskov substitutable, and no examples come to mind where I have found this useful.

The downsides are that it increases cognitive load for reading and understanding a code base, and especially so when debugging where you see the double underscore name in the source and a mangled name in the debugger.

My personal approach is to intentionally avoid it. I work on a very large code base. The rare uses of it stick out like a sore thumb and do not seem justified.

You do need to be aware of it so you know it when you see it.

PEP 8

PEP 8, the Python standard library style guide, currently says (abridged):

There is some controversy about the use of __names.

If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores.

  1. Note that only the simple class name is used in the mangled name, so if a subclass chooses both the same class name and attribute name, you can still get name collisions.

  2. Name mangling can make certain uses, such as debugging and __getattr__() , less convenient. However the name mangling algorithm is well documented and easy to perform manually.

  3. Not everyone likes name mangling. Try to balance the need to avoid accidental name clashes with potential use by advanced callers.

How does it work?

If you prepend two underscores (without ending double-underscores) in a class definition, the name will be mangled, and an underscore followed by the class name will be prepended on the object:

>>> class Foo(object):
...     __foobar = None
...     _foobaz = None
...     __fooquux__ = None
... 
>>> [name for name in dir(Foo) if 'foo' in name]
['_Foo__foobar', '__fooquux__', '_foobaz']

Note that names will only get mangled when the class definition is parsed:

>>> Foo.__test = None
>>> Foo.__test
>>> Foo._Foo__test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute '_Foo__test'

Also, those new to Python sometimes have trouble understanding what’s going on when they can’t manually access a name they see defined in a class definition. This is not a strong reason against it, but it’s something to consider if you have a learning audience.

One Underscore?

If the convention is to use only one underscore, I’d also like to know the rationale.

When my intention is for users to keep their hands off an attribute, I tend to only use the one underscore, but that’s because in my mental model, subclassers would have access to the name (which they always have, as they can easily spot the mangled name anyways).

If I were reviewing code that uses the __ prefix, I would ask why they’re invoking name mangling, and if they couldn’t do just as well with a single underscore, keeping in mind that if subclassers choose the same names for the class and class attribute there will be a name collision in spite of this.


回答 2

我不会说实践会产生更好的代码。可见性修改器只会分散您的注意力,而副作用是会强制您按预期使用界面。一般来说,增强可见性可以防止程序员在没有正确阅读文档的情况下搞乱事情。

一个更好的解决方案是Python鼓励的方法:应该很好地记录您的类和变量,并明确其行为。源应该可用。这是编写代码的更可扩展和可靠的方式。

我在Python中的策略是:

  1. 只需写下该死的东西,就无需假设如何保护您的数据。假定您编写用于创建问题的理想接口。
  2. 使用前导下划线表示可能不会在外部使用且不属于常规“客户端代码”界面的。
  3. 仅在课堂上纯粹方便的事情上使用双下划线,否则,如果不慎将其暴露在外会造成相当大的损害。

最重要的是,应该清楚一切都在做什么。如果其他人会使用它,请记录下来。如果希望一年之内有用,请记录下来。

附带说明,您实际上应该使用其他语言的保护:您永远都不知道您的类以后可能会继承以及它的用途。最好只保护您确定不能或不应被外来代码使用的那些变量。

I wouldn’t say that practice produces better code. Visibility modifiers only distract you from the task at hand, and as a side effect force your interface to be used as you intended. Generally speaking, enforcing visibility prevents programmers from messing things up if they haven’t read the documentation properly.

A far better solution is the route that Python encourages: Your classes and variables should be well documented, and their behaviour clear. The source should be available. This is far more extensible and reliable way to write code.

My strategy in Python is this:

  1. Just write the damn thing, make no assumptions about how your data should be protected. This assumes that you write to create the ideal interfaces for your problems.
  2. Use a leading underscore for stuff that probably won’t be used externally, and isn’t part of the normal “client code” interface.
  3. Use double underscore only for things that are purely convenience inside the class, or will cause considerable damage if accidentally exposed.

Above all, it should be clear what everything does. Document it if someone else will be using it. Document it if you want it to be useful in a year’s time.

As a side note, you should actually be going with protected in those other languages: You never know your class might be inherited later and for what it might be used. Best to only protect those variables that you are certain cannot or should not be used by foreign code.


回答 3

您不应该从私有数据开始,而是在必要时将其公开。相反,您应该首先确定对象的接口。即,您应该首先弄清楚世界所看到的(公共事物),然后弄清楚要实现这一目标需要哪些私人事物。

其他语言很难使曾经公开的语言私有化。也就是说,如果我将变量设为私有或受保护,则会破坏很多代码。但是对于python中的属性,情况并非如此。相反,即使重新排列内部数据,我也可以保持相同的接口。

_和__之间的区别是python实际上试图强制后者。当然,它并不会很努力,但确实会增加难度。拥有_只是告诉其他程序员意图是什么,他们可以无视自己的危险。但是忽略该规则有时会有所帮助。例子包括调试,临时黑客攻击以及使用非您打算使用的第三方代码的方式。

You shouldn’t start with private data and make it public as necessary. Rather, you should start by figuring out the interface of your object. I.e. you should start by figuring out what the world sees (the public stuff) and then figure out what private stuff is necessary for that to happen.

Other language make difficult to make private that which once was public. I.e. I’ll break lots of code if I make my variable private or protected. But with properties in python this isn’t the case. Rather, I can maintain the same interface even with rearranging the internal data.

The difference between _ and __ is that python actually makes an attempt to enforce the latter. Of course, it doesn’t try really hard but it does make it difficult. Having _ merely tells other programmers what the intention is, they are free to ignore at their peril. But ignoring that rule is sometimes helpful. Examples include debugging, temporary hacks, and working with third party code that wasn’t intended to be used the way you use it.


回答 4

对此已经有很多好的答案,但是我将提供另一个答案。这也是对一直说双下划线不是私密的(实际上是私密的)人们的回应。

如果您查看Java / C#,则它们都具有private / protected / public。所有这些都是编译时构造。它们仅在编译时强制执行。如果要在Java / C#中使用反射,则可以轻松访问私有方法。

现在,每次您在Python中调用函数时,本质上都是在使用反射。这些代码在Python中是相同的。

lst = []
lst.append(1)
getattr(lst, 'append')(1)

对于后面的代码,“点”语法只是语法糖。主要是因为仅使用一个函数调用就已经很难使用getattr。从那里变得更糟。

所以就没有了会有Java / C#版本的private,因为Python不会编译代码。Java和C#无法在运行时检查函数是私有的还是公共的,因为该信息已消失(并且不知道从何处调用该函数)。

现在,有了这些信息,双重下划线的名称修饰对于实现“私密性”最有意义。现在,当从“ self”实例调用函数时,它注意到它以“ __”开头,它只是在此处执行名称修改。它只是语法上的糖。该语法糖允许仅使用反射进行数据成员访问的语言中的“私有”等价物。

免责声明:我从没听过Python开发人员说过这样的话。缺乏“私有”的真正原因是文化上的,但是您还将注意到大多数脚本/解释语言没有私有。除了编译时,严格执行的私有方法在任何情况下都不可行。

There are already a lot of good answers to this, but I’m going to offer another one. This is also partially a response to people who keep saying that double underscore isn’t private (it really is).

If you look at Java/C#, both of them have private/protected/public. All of these are compile-time constructs. They are only enforced at the time of compilation. If you were to use reflection in Java/C#, you could easily access private method.

Now every time you call a function in Python, you are inherently using reflection. These pieces of code are the same in Python.

lst = []
lst.append(1)
getattr(lst, 'append')(1)

The “dot” syntax is only syntactic sugar for the latter piece of code. Mostly because using getattr is already ugly with only one function call. It just gets worse from there.

So with that, there can’t be a Java/C# version of private, as Python doesn’t compile the code. Java and C# can’t check if a function is private or public at runtime, as that information is gone (and it has no knowledge of where the function is being called from).

Now with that information, the name mangling of the double underscore makes the most sense for achieving “private-ness”. Now when a function is called from the ‘self’ instance and it notices that it starts with ‘__’, it just performs the name mangling right there. It’s just more syntactic sugar. That syntactic sugar allows the equivalent of ‘private’ in a language that only uses reflection for data member access.

Disclaimer: I have never heard anybody from the Python development say anything like this. The real reason for the lack of “private” is cultural, but you’ll also notice that most scripting/interpreted languages have no private. A strictly enforceable private is not practical at anything except for compile time.


回答 5

第一:为什么要隐藏数据?为什么这么重要?

大多数时候,您并不是真的想这样做,但是您这样做是因为其他人正在这样做。

如果您确实真的不希望别人使用某些东西,请添加一个在其前面下划线。就是这样… Pythonistas知道带有下划线的内容并不能保证每次都能正常工作,并且可能在您不知情的情况下发生变化。

那就是我们的生活方式,我们对此表示满意。

使用两个下划线会使您的类难以继承,甚至您也不想那样工作。

First: Why do you want to hide your data? Why is that so important?

Most of the time you don’t really want to do it but you do because others are doing.

If you really really really don’t want people using something, add one underscore in front of it. That’s it… Pythonistas know that things with one underscore is not guaranteed to work every time and may change without you knowing.

That’s the way we live and we’re okay with that.

Using two underscores will make your class so bad to subclass that even you will not want to work that way.


回答 6

选择的答案很好地解释了属性如何消除对私有属性的需求,但是我还要补充一点,模块级的函数消除了对私有方法的需求

如果在模块级别将方法转换为函数,则将消除子类覆盖它的机会。将某些功能移至模块级别比使用隐藏名称修饰的方法更具Python风格。

The chosen answer does a good job of explaining how properties remove the need for private attributes, but I would also add that functions at the module level remove the need for private methods.

If you turn a method into a function at the module level, you remove the opportunity for subclasses to override it. Moving some functionality to the module level is more Pythonic than trying to hide methods with name mangling.


回答 7

以下代码段将解释所有不同的情况:

  • 两个下划线(__a)
  • 单个前划线(_a)
  • 没有下划线(a)

    class Test:
    
    def __init__(self):
        self.__a = 'test1'
        self._a = 'test2'
        self.a = 'test3'
    
    def change_value(self,value):
        self.__a = value
        return self.__a

打印测试对象的所有有效属性

testObj1 = Test()
valid_attributes = dir(testObj1)
print valid_attributes

['_Test__a', '__doc__', '__init__', '__module__', '_a', 'a', 
'change_value']

在这里,您可以看到__a的名称已更改为_Test__a,以防止任何子类都覆盖此变量。这个概念在python中被称为“名称修改”。您可以这样访问:

testObj2 = Test()
print testObj2._Test__a

test1

同样,在_a情况下,该变量只是通知开发人员应将其用作该类的内部变量,即使您访问python解释器也不会执行任何操作,但这不是一个好习惯。

testObj3 = Test()
print testObj3._a

test2

变量可以像公共类变量一样从任何地方进行访问。

testObj4 = Test()
print testObj4.a

test3

希望答案对您有所帮助:)

Following code snippet will explain all different cases :

  • two leading underscores (__a)
  • single leading underscore (_a)
  • no underscore (a)

    class Test:
    
    def __init__(self):
        self.__a = 'test1'
        self._a = 'test2'
        self.a = 'test3'
    
    def change_value(self,value):
        self.__a = value
        return self.__a
    

printing all valid attributes of Test Object

testObj1 = Test()
valid_attributes = dir(testObj1)
print valid_attributes

['_Test__a', '__doc__', '__init__', '__module__', '_a', 'a', 
'change_value']

Here, you can see that name of __a has been changed to _Test__a to prevent this variable to be overridden by any of the subclass. This concept is known as “Name Mangling” in python. You can access this like this :

testObj2 = Test()
print testObj2._Test__a

test1

Similarly, in case of _a, the variable is just to notify the developer that it should be used as internal variable of that class, the python interpreter won’t do anything even if you access it, but it is not a good practise.

testObj3 = Test()
print testObj3._a

test2

a variable can be accesses from anywhere it’s like a public class variable.

testObj4 = Test()
print testObj4.a

test3

Hope the answer helped you :)


回答 8

乍一看,它应该与其他语言相同(在“其他”下,我指的是Java或C ++),但事实并非如此。

在Java中,您将所有不应在外部访问的变量设为私有。在Python中,由于没有“私密性”,因此您无法实现这一目标(正如Python原则之一所说的:“我们都是成年人”)。因此,双下划线仅表示“伙计,请勿直接使用此字段”。相同的含义是下划线,当您必须从所考虑的类继承时,这不会引起任何头痛(这只是双下划线可能引起的问题的一个示例)。

因此,我建议您默认对“私有”成员使用单个下划线。

At first glance it should be the same as for other languages (under “other” I mean Java or C++), but it isn’t.

In Java you made private all variables that shouldn’t be accessible outside. In the same time in Python you can’t achieve this since there is no “privateness” (as one of Python principles says – “We’re all adults”). So double underscore means only “Guys, do not use this field directly”. The same meaning has singe underscore, which in the same time doesn’t cause any headache when you have to inherit from considered class (just an example of possible problem caused by double underscore).

So, I’d recommend you to use single underscore by default for “private” members.


回答 9

“如果不确定变量是私有变量还是受保护变量,最好选择私有变量。” -是的,在Python中也是如此。

这里有一些关于“约定”的答案,但没有提供这些约定的链接。PEP 8是Python的权威指南,明确指出:

如有疑问,请选择非公开;稍后将其公开比将公共属性设为不公开要容易。

其他答案也考虑了公共和私有之间的区别以及Python中的名称修饰。从同一个链接,

我们在这里不使用术语“私有”,因为在Python中没有任何属性是真正私有的(通常没有不必要的工作量)。

“If in doubt about whether a variable should be private or protected, it’s better to go with private.” – yes, same holds in Python.

Some answers here say about ‘conventions’, but don’t give the links to those conventions. The authoritative guide for Python, PEP 8 states explicitly:

If in doubt, choose non-public; it’s easier to make it public later than to make a public attribute non-public.

The distinction between public and private, and name mangling in Python have been considered in other answers. From the same link,

We don’t use the term “private” here, since no attribute is really private in Python (without a generally unnecessary amount of work).


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