Python 对象名称前的单下划线和双下划线是什么意思?
有人能解释一下Python中在对象名称前加一个和两个前导下划线的确切含义,以及两者之间的区别吗 此外,无论所讨论的对象是变量、函数、方法等,该含义是否保持不变?单下划线 在类中,带有前导下划线的名称只是向其他程序员指示属性或方法是私有的。然而,这个名字本身并没有什么特别之处 引述: _单前导下划线:弱“内部使用”指示器。例如,M import*中的Python 对象名称前的单下划线和双下划线是什么意思?,python,oop,naming-conventions,identifier,Python,Oop,Naming Conventions,Identifier,有人能解释一下Python中在对象名称前加一个和两个前导下划线的确切含义,以及两者之间的区别吗 此外,无论所讨论的对象是变量、函数、方法等,该含义是否保持不变?单下划线 在类中,带有前导下划线的名称只是向其他程序员指示属性或方法是私有的。然而,这个名字本身并没有什么特别之处 引述: _单前导下划线:弱“内部使用”指示器。例如,M import*中的不会导入名称以下划线开头的对象 双下划线(名称混乱) 发件人: 格式为\uuuu spam的任何标识符(至少两个前导下划线,最多一个尾随下划线)以文本
不会导入名称以下划线开头的对象
双下划线(名称混乱)
发件人:
格式为\uuuu spam
的任何标识符(至少两个前导下划线,最多一个尾随下划线)以文本形式替换为\u classname\uuuuu spam
,其中classname
是带前导下划线的当前类名。这种篡改是在不考虑标识符的语法位置的情况下完成的,因此可以使用它来定义类私有实例和类变量、方法、全局变量中存储的变量,甚至实例中存储的变量。在其他类的实例上对此类专用
以及来自同一页面的警告:
名称混乱旨在为类提供一种定义“私有”实例变量和方法的简单方法,而不必担心派生类定义的实例变量,也不必担心类外的代码会弄乱实例变量。请注意,撕碎规则的设计主要是为了避免事故;一个坚定的灵魂仍然有可能访问或修改一个被认为是私有的变量
例子
>>类MyClass():
... 定义初始化(自):
... self.\uu superprivate=“你好”
... self._semiprivate=“,世界!”
...
>>>mc=MyClass()
>>>打印mc.\uuu superprivate
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:myClass实例没有属性“\uu superprivate”
>>>打印mc.\u半私有
世界!
>>>打印命令__
{“我的班级超级私人”:“你好”,“半私人”:“世界!”
单前导下划线是一种惯例。如果名称是否以一个下划线开头,则从解释器的角度来看没有区别
双前导下划线和尾随下划线用于内置方法,如\uuuuu init\uuuuu
,\uuuuuu bool\uuuu
等
带尾随的双前导下划线也是一种惯例,但是,类方法将由解释器执行。对于变量或基本函数名不存在任何差异。\uuuufoo\uuuu
:这只是一种约定,Python系统使用的名称不会与用户名冲突
\u foo
:这只是一种约定,程序员可以通过这种方式指示变量是私有的(无论在Python中是什么意思)
\uuuufoo
:这具有真正的意义:解释器将此名称替换为\u classname\uuuuufoo
,以确保该名称不会与另一个类中的类似名称重叠
在Python世界中,没有其他形式的下划线具有意义
在这些约定中,类、变量、全局等之间没有区别。你的问题很好,不仅仅是关于方法。模块中的函数和对象通常也以一个下划线作为前缀,并且可以以两个下划线作为前缀
但是,例如,双下划线名称在模块中不会被名称损坏。如果从模块(从模块导入*)导入所有名称,则不会导入以一个(或多个)下划线开头的名称,也不会导入帮助(模块)中显示的名称。到目前为止,答案非常好,但缺少一些小贴士。单个前导下划线不仅仅是一种约定:如果您使用foobar import*
中的,并且模块foobar
没有定义\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
列表,则从模块导入的名称中不包含带前导下划线的名称。让我们假设这主要是一个惯例,因为这个案件是一个相当模糊的角落;-)
领先的下划线约定不仅广泛用于私有名称,而且还用于C++所称的受保护的类——例如,完全被类(甚至是强< > < /强>的类的方法的名称要被重写,因为在它们的基类中,代码>引发NoTimePrimeTeDror !-)通常是单个前导下划线名称,用于指示使用该类(或子类)的实例编写,而该类(或子类)不打算直接调用所述方法
例如,要使线程安全队列具有与FIFO不同的排队规则,可以导入队列,将queue.queue子类化,并重写诸如\u get
和\u put
等方法;“客户代码”从不调用那些(“钩子”)方法,而是(“组织”)公共方法,如put
和get
(这就是所谓的设计模式——例如,请参阅基于我关于该主题的一段视频的有趣演示,并添加了成绩单的概要)
编辑:对话描述中的视频链接现在已断开。您可以找到前两个视频和。有时,您会看到一个元组,其前导下划线如中所示
def foo(bar):
return _('my_' + bar)
在本例中,发生的情况是,uz()是本地化函数的别名,该函数根据区域设置对文本进行操作,以将文本转换为正确的语言等。例如,Sphinx就是这样做的,您可以在导入中找到
from sphinx.locale import l_, _
在sphinx.locale中,u()被指定为某些本地化函数的别名。\u变量
是半私有的,仅用于约定<
from sphinx.locale import l_, _
class Test(object):
def __init__(self):
self.__a = 'a'
self._b = 'b'
>>> t = Test()
>>> t._b
'b'
>>> t.__a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'
>>> t._Test__a
'a'
class PrivateVarC(object):
def get_x(self):
pass
def set_x(self, val):
pass
rwvar = property(get_p, set_p)
ronly = property(get_p)
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"
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'
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)
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
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
>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11
>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60
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
_
__
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
class Tire(Circle):
def perimeter(self):
return Circle.perimeter(self) * 1.25
_perimeter = perimeter
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)
# 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'>