对象名称前的单下划线和双下划线的含义是什么?

发布于 2024-08-02 06:26:27 字数 35 浏览 9 评论 0原文

Python 中对象名称前的单下划线和双下划线代表什么?

What do single and double leading underscores before an object's name represent in Python?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

草莓味的萝莉 2024-08-09 06:26:27

单下划线

在类中,带有前导下划线的名称向其他程序员表明该属性或方法旨在在该类中使用。然而,隐私并没有以任何方式强制
在模块中的函数中使用前导下划线表示不应从其他地方导入它。

来自 PEP-8 风格指南:

_single_leading_underscore:弱“内部使用”指示器。例如 from M import * 不会导入名称以下划线开头的对象。

双下划线(名称修改)

来自 Python 文档

__spam 形式的任何标识符(至少两个前导下划线,最多一个尾随下划线)在文本上替换为 _classname__spam,其中 classname 是当前类名,去掉了前导下划线。这种修改是在不考虑标识符的语法位置的情况下完成的,因此它可以用于定义类私有实例和类变量、方法、存储在全局变量中的变量,甚至存储在实例中的变量。在其他类的实例上该类是私有的。

以及来自同一页面的警告:

名称修饰的目的是为类提供一种简单的方法来定义“私有”实例变量和方法,而不必担心派生类定义的实例变量,或通过类外部的代码破坏实例变量。请注意,损坏规则主要是为了避免事故而设计的; 坚定的灵魂仍然有可能访问或修改被视为私有的变量。

示例

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

Single Underscore

In a class, names with a leading underscore indicate to other programmers that the attribute or method is intended to be be used inside that class. However, privacy is not enforced in any way.
Using leading underscores for functions in a module indicates it should not be imported from somewhere else.

From the PEP-8 style guide:

_single_leading_underscore: weak "internal use" indicator. E.g. from M import * does not import objects whose name starts with an underscore.

Double Underscore (Name Mangling)

From the Python docs:

Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, so it can be used to define class-private instance and class variables, methods, variables stored in globals, and even variables stored in instances. private to this class on instances of other classes.

And a warning from the same page:

Name mangling is intended to give classes an easy way to define “private” instance variables and methods, without having to worry about instance variables defined by derived classes, or mucking with instance variables by code outside the class. Note that the mangling rules are designed mostly to avoid accidents; it still is possible for a determined soul to access or modify a variable that is considered private.

Example

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
醉生梦死 2024-08-09 06:26:27
  • _foo:只是一个约定。程序员表明该变量是私有的(无论这在 Python 中意味着什么)。

  • __foo:这有实际意义。解释器将此名称替换为 _classname__foo,以确保该名称不会与另一个类中的类似名称重叠。

  • __foo__:只是一个约定。 Python系统使用不会与用户名冲突的名称的一种方式。

在 Python 世界中,其他形式的下划线都没有意义。此外,在这些约定中,类、变量、全局等之间没有区别。

  • _foo: Only a convention. A way for the programmer to indicate that the variable is private (whatever that means in Python).

  • __foo: This has real meaning. The interpreter replaces this name with _classname__foo as a way to ensure that the name will not overlap with a similar name in another class.

  • __foo__: Only a convention. A way for the Python system to use names that won't conflict with user names.

No other form of underscores have meaning in the Python world. Also, there's no difference between class, variable, global, etc in these conventions.

蓝礼 2024-08-09 06:26:27

到目前为止,答案很好,但缺少一些花絮。单个前导下划线并不完全只是一种约定:如果您使用 from foobar import *,并且模块 foobar 没有定义 __all__ 列表中,从模块导入的名称包含以下划线开头的名称。假设这主要是一种约定,因为这个案例是一个相当不起眼的角落;-)。

前导下划线约定不仅广泛用于私有名称,而且还用于 C++ 称为受保护的名称 - 例如,完全旨在被子类覆盖(即使是必须被覆盖的子类,因为在基类中它们引发NotImplementedError!-)通常是单前导下划线名称来指示代码<使用该类(或子类)的实例,该方法并不意味着直接调用。

例如,要创建一个具有与 FIFO 不同的排队规则的线程安全队列,可以导入 Queue,子类化 Queue.Queue,并重写诸如 _get_put 之类的方法; “客户端代码”从不调用这些(“钩子”)方法,而是调用(“组织”)公共方法,例如 putget (这称为 < a href="http://en.wikipedia.org/wiki/Template_method_pattern" rel="noreferrer">模板方法设计模式 - 请参见 此处 提供了一个有趣的演示,该演示基于我关于该主题的演讲视频,并添加了抄本摘要)。

编辑:演讲描述中的视频链接现已损坏。您可以在此处此处

Excellent answers so far but some tidbits are missing. A single leading underscore isn't exactly just a convention: if you use from foobar import *, and module foobar does not define an __all__ list, the names imported from the module do not include those with a leading underscore. Let's say it's mostly a convention, since this case is a pretty obscure corner;-).

The leading-underscore convention is widely used not just for private names, but also for what C++ would call protected ones -- for example, names of methods that are fully intended to be overridden by subclasses (even ones that have to be overridden since in the base class they raise NotImplementedError!-) are often single-leading-underscore names to indicate to code using instances of that class (or subclasses) that said methods are not meant to be called directly.

For example, to make a thread-safe queue with a different queueing discipline than FIFO, one imports Queue, subclasses Queue.Queue, and overrides such methods as _get and _put; "client code" never calls those ("hook") methods, but rather the ("organizing") public methods such as put and get (this is known as the Template Method design pattern -- see e.g. here for an interesting presentation based on a video of a talk of mine on the subject, with the addition of synopses of the transcript).

Edit: The video links in the description of the talks are now broken. You can find the first two videos here and here.

暖风昔人 2024-08-09 06:26:27

._variable 是半私有的,仅用于约定

.__variable 通常被错误地视为超私有,而其实际含义只是为了命名以防止意外访问 [1]

.__variable__ 通常是为内置方法或变量保留

如果您迫切需要,您仍然可以访问 .__mangled 变量。双下划线只是将变量命名或重命名为 instance._className__mangled

示例:

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b 是可访问的,因为它只是按照约定隐藏

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t.__a 找不到,因为它不再存在由于 namemangling

>>> t._Test__a
'a'

通过访问 instance._className__variable 而不仅仅是双下划线名称,您可以访问隐藏值

._variable is semiprivate and meant just for convention

.__variable is often incorrectly considered superprivate, while its actual meaning is just to namemangle to prevent accidental access[1]

.__variable__ is typically reserved for builtin methods or variables

You can still access .__mangled variables if you desperately want to. The double underscores just namemangles, or renames, the variable to something like instance._className__mangled

Example:

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b is accessible because it is only hidden by convention

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t.__a isn't found because it no longer exists due to namemangling

>>> t._Test__a
'a'

By accessing instance._className__variable instead of just the double underscore name, you can access the hidden value

断舍离 2024-08-09 06:26:27

开头单下划线:

Python 没有真正的私有方法。相反,方法或属性名称开头的一个下划线意味着您不应访问此方法,因为它不是 API 的一部分。

class BaseForm(StrAndUnicode):
    
    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

(此代码片段取自 Django 源代码:django/forms/forms.py)。在此代码中,errors 是公共属性,但该属性调用的方法 _get_errors 是“私有”的,因此您不应访问它。

开头有两个下划线:

这会引起很多混乱。它不应该用于创建私有方法。它应该用于避免您的方法被子类覆盖或意外访问。让我们看一个例子:

class A(object):
    def __test(self):
        print "I'm a test method in class A"

    def test(self):
        self.__test()
 
a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!

输出:

$ python test.py
I'm test method in class A
I'm test method in class A

现在创建一个子类 B 并为 __test 方法进行定制

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

输出将是...

$ python test.py
I'm test method in class A

正如我们所见,B.test() 没有像我们预期的那样调用 B.__test() 方法。但事实上,这是 __ 的正确行为。名为 __test() 的两个方法会自动重命名(损坏)为 _A__test() 和 _B__test(),因此它们不会意外覆盖。当您创建以 __ 开头的方法时,这意味着您不希望任何人能够覆盖它,并且您只想从它自己的类内部访问它。

开头和结尾各有两个下划线:

当我们看到像__this__这样的方法时,不要调用它。这是 Python 应该调用的方法,而不是您。让我们看一下:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

总有一个运算符或本机函数调用这些魔术方法。有时它只是特定情况下 Python 调用的一个钩子。例如,在调用 __new__() 构建实例之后创建对象时,会调用 __init__()...

让我们举个例子...

class FalseCalculator(object):

    def __init__(self, number):
        self.number = number

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number

number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

有关更多详细信息,请参阅 PEP-8 指南 。有关更多魔术方法,请参阅此 PDF

Single underscore at the beginning:

Python doesn't have real private methods. Instead, one underscore at the start of a method or attribute name means you shouldn't access this method, because it's not part of the API.

class BaseForm(StrAndUnicode):
    
    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

(This code snippet was taken from Django source code: django/forms/forms.py). In this code, errors is a public property, but the method this property calls, _get_errors, is "private", so you shouldn't access it.

Two underscores at the beginning:

This causes a lot of confusion. It should not be used to create a private method. It should be used to avoid your method being overridden by a subclass or accessed accidentally. Let's see an example:

class A(object):
    def __test(self):
        print "I'm a test method in class A"

    def test(self):
        self.__test()
 
a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!

Output:

$ python test.py
I'm test method in class A
I'm test method in class A

Now create a subclass B and do customization for __test method

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

The output will be...

$ python test.py
I'm test method in class A

As we have seen, B.test() didn't call B.__test() methods, as we might expect. But in fact, this is the correct behavior for __. The two methods called __test() are automatically renamed (mangled) to _A__test() and _B__test(), so they do not accidentally override. When you create a method starting with __ it means that you don't want anyone to be able to override it, and you only intend to access it from inside its own class.

Two underscores at the beginning and at the end:

When we see a method like __this__, don't call it. This is a method which Python is meant to call, not you. Let's take a look:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

There is always an operator or native function which calls these magic methods. Sometimes it's just a hook Python calls in specific situations. For example __init__() is called when the object is created after __new__() is called to build the instance...

Let's take an example...

class FalseCalculator(object):

    def __init__(self, number):
        self.number = number

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number

number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

For more details, see the PEP-8 guide. For more magic methods, see this PDF.

浅笑轻吟梦一曲 2024-08-09 06:26:27

根据 Python 中下划线的含义

  • 单前导下划线(< code>_var):命名约定,指示名称供内部使用。通常不由 Python 解释器强制执行(通配符导入除外),仅作为对程序员的提示。
  • 单尾下划线(var_):按惯例使用以避免与Python关键字发生命名冲突。
  • 双前导下划线(__var):在类上下文中使用时触发名称修改。由 Python 解释器强制执行。
  • 双前导和尾随下划线(__var__):表示Python语言定义的特殊方法。避免为您自己的属性采用这种命名方案。
  • 单下划线(_):有时用作临时或无关紧要的变量的名称(“不关心”)。另外:Python REPL 中最后一个表达式的结果。

According to Meaning of Underscores in Python

  • Single Leading Underscore(_var): Naming convention indicating a name is meant for internal use. Generally not enforced by the Python interpreter (except in wildcard imports) and meant as a hint to the programmer only.
  • Single Trailing Underscore(var_): Used by convention to avoid naming conflicts with Python keywords.
  • Double Leading Underscore(__var): Triggers name mangling when used in a class context. Enforced by the Python interpreter.
  • Double Leading and Trailing Underscore(__var__): Indicates special methods defined by the Python language. Avoid this naming scheme for your own attributes.
  • Single Underscore(_): Sometimes used as a name for temporary or insignificant variables (“don’t care”). Also: The result of the last expression in a Python REPL.
何以畏孤独 2024-08-09 06:26:27

由于很多人都在参考 Raymond 的演讲,我就简单说一下写下他说的话会更容易一些:

双下划线的目的不是为了隐私。目的是像这样使用它

类 Circle(对象):

    def __init__(自身,半径):
        self.radius = 半径

    定义区域(自身):
        p = self.__周长()
        r = p / 数学.pi / 2.0
        返回math.pi * r ** 2.0

    定义周长(自身):
        返回 2.0 * math.pi * self.radius

    __perimeter = 周长 # 局部参考


轮胎类别(圆):

    定义周长(自身):
        返回 Circle.perimeter(self) * 1.25

这实际上与隐私相反,这都是关于自由的。它使您的子类可以自由地重写任何一种方法,而不会破坏其他方法

假设您没有在 Circle 中保留 perimeter 的本地引用。现在,派生类 Tire 重写了 perimeter 的实现,而不触及 area。当您调用 Tire(5).area() 时,理论上它应该仍然使用 Circle.perimeter 进行计算,但实际上它使用 Tire.perimeter,这不是预期的行为。这就是为什么我们需要 Circle 中的本地引用。

但为什么是__perimeter而不是_perimeter呢?因为 _perimeter 仍然为派生类提供了重写的机会:

class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

    _perimeter = perimeter

双下划线具有名称修改,因此父类中的本地引用在派生类中被重写的机会很小。因此“使您的子类可以自由地重写任何一种方法,而不会破坏其他方法”。

如果您的类不会被继承,或者方法重写不会破坏任何内容,那么您根本不需要 __double_leading_underscore

Since so many people are referring to Raymond's talk, I'll just make it a little easier by writing down what he said:

The intention of the double underscores was not about privacy. The intention was to use it exactly like this

class Circle(object):

    def __init__(self, radius):
        self.radius = radius

    def area(self):
        p = self.__perimeter()
        r = p / math.pi / 2.0
        return math.pi * r ** 2.0

    def perimeter(self):
        return 2.0 * math.pi * self.radius

    __perimeter = perimeter  # local reference


class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

It's actually the opposite of privacy, it's all about freedom. It makes your subclasses free to override any one method without breaking the others.

Say you don't keep a local reference of perimeter in Circle. Now, a derived class Tire overrides the implementation of perimeter, without touching area. When you call Tire(5).area(), in theory it should still be using Circle.perimeter for computation, but in reality it's using Tire.perimeter, which is not the intended behavior. That's why we need a local reference in Circle.

But why __perimeter instead of _perimeter? Because _perimeter still gives derived class the chance to override:

class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

    _perimeter = perimeter

Double underscores has name mangling, so there's a very little chance that the local reference in parent class get override in derived class. thus "makes your subclasses free to override any one method without breaking the others".

If your class won't be inherited, or method overriding does not break anything, then you simply don't need __double_leading_underscore.

夜巴黎 2024-08-09 06:26:27

有时您会看到一个带有前导下划线的元组,如在

def foo(bar):
    return _('my_' + bar)

本例中,发生的情况是 _() 是本地化函数的别名,该函数对文本进行操作以将其转换为正确的语言等。语言环境。例如,Sphinx 就是这样做的,您会发现在导入

from sphinx.locale import l_, _

和 sphinx.locale 中,_() 被指定为某些本地化函数的别名。

Sometimes you have what appears to be a tuple with a leading underscore as in

def foo(bar):
    return _('my_' + bar)

In this case, what's going on is that _() is an alias for a localization function that operates on text to put it into the proper language, etc. based on the locale. For example, Sphinx does this, and you'll find among the imports

from sphinx.locale import l_, _

and in sphinx.locale, _() is assigned as an alias of some localization function.

几度春秋 2024-08-09 06:26:27
  • _var:Python 中以单下划线开头的变量是经典变量,旨在通知其他使用您代码的人该变量应保留供内部使用。它们与经典变量有一点不同:在定义它们的对象/模块中进行通配符导入时,不会导入它们(定义 __all__ 变量)。例如:

    # foo.py
    
    变量=“变量”
    _var =“_var”
    
    # bar.py
    
    从 foo 导入 *
    
    print(dir()) # 已定义对象的列表,包含 'var' 但不包含 '_var'
    打印(var)#var
    print(_var) # NameError: 名称 '_var' 未定义
    
  • _ :单下划线是前导单下划线变量的特殊情况。按照惯例,它被用作垃圾变量,用于存储以后不打算访问的值。它也不是通过通配符导入来导入的。例如:这个 for 循环打印“我不能在课堂上讲话”10 次,并且永远不需要访问 _ 变量。

    对于范围 (10) 内的 _:
        print("我不能在课堂上说话")
    
  • var_:单个尾随下划线变量。它们是按惯例使用的经典变量,以避免与 Python 关键字冲突。例如:

    class_ = "MyClassName"
    
  • __var:双前导下划线变量(至少两个前导下划线,最多一个尾随下划线)。当用作类属性(变量和方法)时,这些变量会受到名称修改的影响:在类之外,Python 会将属性重命名为 ___。示例:

    类 MyClass:
        __an_attribute = "属性值"
    
    my_class = MyClass()
    print(my_class._MyClass__an_attribute) # “属性值”
    print(my_class.__an_attribute) # AttributeError: 'MyClass' 对象没有属性 '__an_attribute'
    

    当在类外部用作变量时,它们的行为类似于单个前导下划线变量。

  • __var__:双前导和尾随下划线变量(至少两个前导和尾随下划线)。也称为dunders。 python 使用此命名约定在内部定义变量。避免使用此约定来防止 python 更新可能出现的名称冲突。 Dunder 变量的行为类似于单个前导下划线变量:它们在类内部使用时不受名称修改的影响,但不会在通配符导入中导入。

  • _var: variables with a leading single underscore in python are classic variables, intended to inform others using your code that this variable should be reserved for internal use. They differ on one point from classic variables: they are not imported when doing a wildcard import of an object/module where they are defined (exceptions when defining the __all__ variable). Eg:

    # foo.py
    
    var = "var"
    _var = "_var"
    
    # bar.py
    
    from foo import *
    
    print(dir())  # list of defined objects, contains 'var' but not '_var'
    print(var)    # var
    print(_var)   # NameError: name '_var' is not defined
    
  • _ : the single underscore is a special case of the leading single underscore variables. It is used by convention as a trash variable, to store a value that is not intended to be later accessed. It is also not imported by wildcard imports. Eg: this for loop prints "I must not talk in class" 10 times, and never needs to access the _ variable.

    for _ in range(10):
        print("I must not talk in class")
    
  • var_: single trailing underscore variables. They are classic variables used by convention to avoid conflicts with Python keyword. Eg:

    class_ = "MyClassName"
    
  • __var: double leading underscore variables (at least two leading underscores, at most one trailing underscore). When used as class attributes (variables and methods), these variables are subject to name mangling: outside of the class, python will rename the attribute to _<Class_name>__<attribute_name>. Example:

    class MyClass:
        __an_attribute = "attribute_value"
    
    my_class = MyClass()
    print(my_class._MyClass__an_attribute)  # "attribute_value"
    print(my_class.__an_attribute)  # AttributeError: 'MyClass' object has no attribute '__an_attribute'
    

    When used as variables outside a class, they behave like single leading underscore variables.

  • __var__: double leading and trailing underscore variables (at least two leading and trailing underscores). Also called dunders. This naming convention is used by python to define variables internally. Avoid using this convention to prevent name conflicts that could arise with python updates. Dunder variables behave like single leading underscore variables: they are not subject to name mangling when used inside classes, but are not imported in wildcard imports.

全部不再 2024-08-09 06:26:27

如果确实想将变量设置为只读,恕我直言,最好的方法是使用 property() ,仅将 getter 传递给它。使用 property() 我们可以完全控制数据。

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

我知道OP问了一个不同的问题,但由于我发现另一个问题询问“如何设置私有变量”,与这个问题标记重复,我想在这里添加这个附加信息。

If one really wants to make a variable read-only, IMHO the best way would be to use property() with only getter passed to it. With property() we can have complete control over the data.

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

I understand that OP asked a little different question but since I found another question asking for 'how to set private variables' marked duplicate with this one, I thought of adding this additional info here.

时光磨忆 2024-08-09 06:26:27

很好的答案,而且都是正确的。我提供了简单的示例以及简单的定义/含义。

含义:

some_variable --► 它是公开的,任何人都可以看到它。

_some_variable --► 它是公开的,任何人都可以看到它,但这是表示私有的约定...警告Python 不执行任何强制操作。

__some_varaible --► Python 用 _classname__some_varaible 替换变量名(又名名称修改),它减少/隐藏它的可见性,并且更像私有变量。

老实说根据Python文档

““私有”实例变量只能从
Python 中不存在对象内部”

示例:

class A():
    here="abc"
    _here="_abc"
    __here="__abc"


aObject=A()
print(aObject.here) 
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable 
#print(aObject.__here)

Great answers and all are correct.I have provided simple example along with simple definition/meaning.

Meaning:

some_variable --► it's public anyone can see this.

_some_variable --► it's public anyone can see this but it's a convention to indicate private...warning no enforcement is done by Python.

__some_varaible --► Python replaces the variable name with _classname__some_varaible (AKA name mangling) and it reduces/hides it's visibility and be more like private variable.

Just to be honest here According to Python documentation

"“Private” instance variables that cannot be accessed except from
inside an object don’t exist in Python"

The example:

class A():
    here="abc"
    _here="_abc"
    __here="__abc"


aObject=A()
print(aObject.here) 
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable 
#print(aObject.__here)
难以启齿的温柔 2024-08-09 06:26:27

下面是一个简单的说明性示例,说明双下划线属性如何影响继承的类。因此,通过以下设置:

class parent(object):
    __default = "parent"
    def __init__(self, name=None):
        self.default = name or self.__default

    @property
    def default(self):
        return self.__default

    @default.setter
    def default(self, value):
        self.__default = value


class child(parent):
    __default = "child"

如果您随后在 python REPL 中创建一个子实例,您将看到下面的内容

child_a = child()
child_a.default            # 'parent'
child_a._child__default    # 'child'
child_a._parent__default   # 'parent'

child_b = child("orphan")
## this will show 
child_b.default            # 'orphan'
child_a._child__default    # 'child'
child_a._parent__default   # 'orphan'

这对某些人来说可能是显而易见的,但在更复杂的环境中它让我措手不及

Here is a simple illustrative example on how double underscore properties can affect an inherited class. So with the following setup:

class parent(object):
    __default = "parent"
    def __init__(self, name=None):
        self.default = name or self.__default

    @property
    def default(self):
        return self.__default

    @default.setter
    def default(self, value):
        self.__default = value


class child(parent):
    __default = "child"

if you then create a child instance in the python REPL, you will see the below

child_a = child()
child_a.default            # 'parent'
child_a._child__default    # 'child'
child_a._parent__default   # 'parent'

child_b = child("orphan")
## this will show 
child_b.default            # 'orphan'
child_a._child__default    # 'child'
child_a._parent__default   # 'orphan'

This may be obvious to some, but it caught me off guard in a much more complex environment

挽清梦 2024-08-09 06:26:27

单前导下划线是一种约定。从解释器的角度来看,名称是否以下划线开头没有区别。

双前导和尾随下划线用于内置方法,例如 __init____bool__ 等。

双前导下划线不带尾随对应项也是一种约定,但是,类方法将被解释器mangled。对于变量或基本函数名称不存在差异。

Single leading underscores is a convention. there is no difference from the interpreter's point of view if whether names starts with a single underscore or not.

Double leading and trailing underscores are used for built-in methods, such as __init__, __bool__, etc.

Double leading underscores w/o trailing counterparts are a convention too, however, the class methods will be mangled by the interpreter. For variables or basic function names no difference exists.

流殇 2024-08-09 06:26:27

你的问题问得好,不仅仅是方法问题。模块中的函数和对象通常也以一个下划线为前缀,并且可以以两个下划线为前缀。

但是,例如,__double_underscore 名称在模块中不会被名称破坏。发生的情况是,如果从模块导入所有名称(from module import *),则不会导入以一个(或多个)下划线开头的名称,help(module) 中也不会显示名称。

Your question is good, it is not only about methods. Functions and objects in modules are commonly prefixed with one underscore as well, and can be prefixed by two.

But __double_underscore names are not name-mangled in modules, for example. What happens is that names beginning with one (or more) underscores are not imported if you import all from a module (from module import *), nor are the names shown in help(module).

秋风の叶未落 2024-08-09 06:26:27

Python 中不存在除了从对象内部之外无法访问的“私有”实例变量。然而,大多数 Python 代码都遵循一个约定:以下划线前缀的名称(例如 _spam)应被视为 API 的非公共部分(无论是函数、方法还是数据成员) 。它应被视为实施细节,如有更改,恕不另行通知。

参考
https://docs.python.org /2/tutorial/classes.html#private-variables-and-class-local-references

“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.

reference
https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

与君绝 2024-08-09 06:26:27

获取 _ 和 __ 的事实非常容易;其他答案很好地表达了它们。其用途更难确定。

我是这样看的:

_

应该用来表明某个函数不供公共使用,例如 API。这个和导入限制使它的行为与 C# 中的 internal 非常相似。

__

应该用于避免继承层次结构中的名称冲突并避免后期绑定。很像 c# 中的 private。

==>

如果您想表明某些内容不供公共使用,但其行为应类似于 protected,请使用 _
如果您想表明某些内容不供公共使用,但其行为应类似于 private,请使用 __

这也是我非常喜欢的一句话:

问题是类的作者可能合理地认为“这个
属性/方法名称应该是私有的,只能从内部访问
这个类定义”并使用 __private 约定。但后来,
该类的用户可以创建一个合法需要的子类
访问该名称。所以要么必须修改超类
(这可能很困难或不可能),或者子类代码必须
使用手动修改的名称(这充其量是丑陋且脆弱的)。

但我认为,这样做的问题是,如果没有 IDE 在您重写方法时发出警告,那么如果您不小心重写了基类中的方法,则可能需要一段时间才能找到错误。

Getting the facts of _ and __ is pretty easy; the other answers express them pretty well. The usage is much harder to determine.

This is how I see it:

_

Should be used to indicate that a function is not for public use as for example an API. This and the import restriction make it behave much like internal in c#.

__

Should be used to avoid name collision in the inheritace hirarchy and to avoid latebinding. Much like private in c#.

==>

If you want to indicate that something is not for public use, but it should act like protected use _.
If you want to indicate that something is not for public use, but it should act like private use __.

This is also a quote that I like very much:

The problem is that the author of a class may legitimately think "this
attribute/method name should be private, only accessible from within
this class definition" and use the __private convention. But later on,
a user of that class may make a subclass that legitimately needs
access to that name. So either the superclass has to be modified
(which may be difficult or impossible), or the subclass code has to
use manually mangled names (which is ugly and fragile at best).

But the problem with that is in my opinion that if there's no IDE that warns you when you override methods, finding the error might take you a while if you have accidentially overriden a method from a base-class.

愁杀 2024-08-09 06:26:27

对于方法,您可以使用双下划线通过以下模式隐藏私有“方法”:

# Private methods of MyClass
def _MyClass__do_something(obj:'MyClass'):
    print('_MyClass__do_something() called. type(obj) = {}'.format(type(obj)))

class MyClass():
    def __init__(self):
        __do_something(self)

mc = MyClass()

输出:

_MyClass__do_something() called. type(obj) = <class '__main__.MyClass'>

今天,当我尝试对类方法使用双下划线并得到 NameError: name ' 时,我偶然发现了这一点_<类><方法>'未定义错误。

In the case of methods, you can use the double underscore to hide away private 'methods' with the following pattern:

# Private methods of MyClass
def _MyClass__do_something(obj:'MyClass'):
    print('_MyClass__do_something() called. type(obj) = {}'.format(type(obj)))

class MyClass():
    def __init__(self):
        __do_something(self)

mc = MyClass()

Output:

_MyClass__do_something() called. type(obj) = <class '__main__.MyClass'>

I stumbled across this today when I tried using double underscore for class methods and got the NameError: name '_<class><method>' is not defined error.

儭儭莪哋寶赑 2024-08-09 06:26:27

为了用简单的话来表达它,让我们将 python 变量的可访问性约定与 Java 中的访问修饰符进行比较:

(Python)                                     =   (Java)
_single_underscore_variable                  =   Protected (Accessible to class and its subclasses)
__double_underscore_variable                 =   Private (Accessible to class itself only)
no_underscore_variable                       =   Public (Accessible anywhere)

参考https://www.tutorialsteacher.com/python/public-private-protected-modifiers

To frame it in simple words, let us compare python's variables' accessibility conventions to access modifiers in Java:

(Python)                                     =   (Java)
_single_underscore_variable                  =   Protected (Accessible to class and its subclasses)
__double_underscore_variable                 =   Private (Accessible to class itself only)
no_underscore_variable                       =   Public (Accessible anywhere)

Reference: https://www.tutorialsteacher.com/python/public-private-protected-modifiers

Hello爱情风 2024-08-09 06:26:27

_obj 表示受保护(可以在定义类及其子类内访问)

--obj 表示私有(它们不能从定义它们的类外部直接访问。但是,Python 并不像其他一些语言那样强制执行严格的私有访问;相反,它执行名称重整,使访问变得更加困难,但并非不可能。)

重整是 Python 中的一项功能,它修改类成员的名称,以使其更难从类外部直接访问。这是一种用于创建“伪私有”变量和方法的技术。这是通过在成员名称前加上双下划线 (__) 前缀但不以另一个双下划线结尾来完成的

_obj means protected (can be accessed within the defining class and its subclasses)

--obj means private (They are not directly accessible from outside the class where they are defined. However, Python does not enforce strict private access like some other languages do; instead, it performs name mangling to make access more difficult but not impossible.)

Mangling is a feature in Python that modifies the name of a class member to make it harder to access directly from outside the class. It's a technique used to create "pseudo-private" variables and methods. This is done by prefixing the member name with a double underscore (__) but not ending with another double underscore

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文