python下划线

python下划线

python代码里的_ 下划线

我终于把Python中下划线的含义弄清楚了(憋了很久了)

1. 前单下划线: _var

变量或方法名加 单下划线:

变量或方法名加 单下划线 时,向其他程序员的提示,即以单个下划线开头的变量或方法供内部使用(表示私有),这不是Python强制执行的,直接访问也是可以访问的。

举例:

1
2
3
4
class Test:
def __init__(self):
self.foo = 11
self._bar = 23

如果你实例化这个类并试图访问它的构造函数中定义的foo和_bar属性,会发生什么?让我们来看看:

1
2
3
4
5
>>> t = Test()
>>> t.foo
11
>>> t._bar
23

看到_bar中的前一个下划线并没有阻止我们“进入”类并访问该变量的值。

这是因为Python中的单个下划线前缀仅仅是一种约定。

函数单下划线 从模块导入:

举例:

1
2
3
4
5
6
# This is my_module.py:
def external_func():
return 23

def _internal_func():
return 42

现在,如果使用通配符导入来从模块中导入所有名称,Python将不会导入带有前导下划线的名称(除非模块定义了覆盖此行为的_all__列表):

1
2
3
4
5
>>> from my_module import *
>>> external_func()
23
>>> _internal_func()
NameError: "name '_internal_func' is not defined"

顺便说一下,应该避免通配符导入,因为它们使名称空间中出现的名称变得不清楚。

与通配符导入不同,常规导入不受主要的单下划线命名约定的影响:

1
2
3
4
5
>>> import my_module
>>> my_module.external_func()
23
>>> my_module._internal_func()
42

单下划线是一种Python命名约定,表示某个名称是供内部使用的。它通常不是由Python解释器强制执行的,只是对程序员的提示。

2. 后单下划线: var_

有时候,一个变量最合适的名字已经被一个关键字代替了。因此,类或def之类的名称在Python中不能用作变量名。在这种情况下,你可以添加一个下划线打破命名冲突:

1
2
3
4
5
>>> def make_object(name, class):
SyntaxError: "invalid syntax"

>>> def make_object(name, class_):
... pass

总之,惯例使用单个尾划线(后缀)来避免与Python关键字的命名冲突。在PEP 8中解释了这种约定。

3.前双下划线: __var

这个比较特殊!python会改变其 变量、方法 名!

双下划线前缀导致Python解释器重写属性名,以避免子类中的命名冲突。

这也叫做名字拼写——解释器改变变量的名字的方式使得在以后扩展类时很难产生冲突。

举例:

1
2
3
4
5
class XHX:
def __init__(self):
self.foo = 11
self._bar = 23
self.__baz = 23

让我们看看这个对象的属性使用内置的dir()函数:

1
2
>>> dir(XHX())
['_XHX__baz', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bar', 'foo']

这会给我们一个带有对象属性的列表。让我们看看这个列表:

self.foo在属性列表中,foo变量显示为未修改的foo。

self._bar的行为方式是一样的,它在类中显示为_bar。就像我之前说的,前导下划线只是一种惯例。给程序员的提示。

self.__baz看起来有点不同。当在该列表中搜索_baz时,将看到没有具有该名称的变量。它变成了 _XHX__baz!也就是 _类名__变量名

前面多了一个类名了!这是Python解释器应用的命名混乱。这样做是为了保护变量不被子类覆盖。

举例:

1
2
3
4
5
6
7
8
9
10
11
class ManglingTest:
def __init__(self):
self.__mangled = 'hello'

def get_mangled(self):
return self.__mangled

>>> ManglingTest().get_mangled()
'hello'
>>> ManglingTest().__mangled # 应该用:ManglingTest()._ManglingTest__mangled
AttributeError: "'ManglingTest' object has no attribute '__mangled'"

如果这里没有用下划线,假设变量名叫 self.mangled,ManglingTest().mangled就可以正常返回的。

并且不止是变量,方法(函数)也会变!

举例:

1
2
3
4
5
6
7
8
9
10
11
class MangledMethod:
def __method(self):
return 42

def call_it(self):
return self.__method()

>>> MangledMethod().__method() # 应该用:MangledMethod()._MangledMethod__method()
AttributeError: "'MangledMethod' object has no attribute '__method'"
>>> MangledMethod().call_it()
42

4. 前后双下划线__var__

表示由Python语言定义的特殊方法。避免为自己的属性使用此命名方案。

也叫“魔法函数”,也就是python内置的函数,尽量避免自己写函数时写这种前后双下划线的形式。

python调用C++的_ 下划线

import一个下划线的包

1
import _wenet

这是在C++里写了这个module模块,python绑定了这个C++模块,在python里import时用的是加下划线的写法。