Python中下划线“_”有什么含义?
在Python的变量名和方法名中经常会看到下划线的使用,有时是单下划线,有时是双下划线。对此你可能有些疑惑:“Python中的下划线到底有什么含义?”
本文将竭力为您解释清楚Python中下划线到底有什么含义。
Python中基本上有以下5种下划线约定模式:
- 前置的单下划线:_var
- 后置单下划线:var_
- 前置双下划线:__var
- 前后双下划线:var
- 单独的下划线:_
就影响而言,下划线分为以下两类:
- 对程序运行没有影响:这种仅仅是一种约定,用于提示开发人员。
- 对程序运行有影响:这种对Python解释器有特别的含义,随意更改会影响程序的运行。
接下来为您详细解释着5中下划线模式的涵义。
Python 前置单下划线:_var
一般情况下,前置的单下划线是程序员之间一种默契的约定。当它出现在变量名或方法名中时,意思是提示其他程序员:这个变量或方法是私有的,只在内部使用。(PEP 8(最常用的Python代码风格指南。)中定义了这个约定)。
不过,这个约定对Python解释器来说没有意义。与Java等高级语言不通,Python当中并没有“公共”或“私有”之类的概念,所以前置的单下划线对程序运行几乎没有影响(后续再解释这里为什么用“几乎”这个词)。
我们看以下代码:
class Site:
def __init__(self):
self.name = 'Python技术站'
self._url = 'http://www.pythonjishu.com'
demo = Site()
#访问两个属性
print(demo.name)
print(demo._url)
运行结果:
Python技术站
http://www.pythonjishu.com
可以看到,_url前面的单下划线并没有影响我们访问这个变量的值。
基本上,我们对Python中的前置单下划线的认知,可以到此为止了。
前面我们讲过,前置的单下划线对程序运行几乎没有影响。之所以用“几乎”一词,是因为在某些时候,Python解释器又承认了前置单下划线表示的是“内部使用”的意思,导致使用前置单下划线的变量或方法无法访问!
这个特殊的情况是发生在我们从其他库中导入模块的时候。
当我们使用通配符导入方式导入模块时,Python不会导入带有前置单下划线的方法或变量。
举个例子,比如在一个名为demo_module的模块中有以下代码:
# demo_module.py:
def external_func():
return 'Python技术站'
def _internal_func():
return 'http://www.pythonjishu.com'
现在,如果使用通配符导入这个模块,Python不会把带有前置单下划线的方法导入进来。也就是说,无法访问到 demo_module 的 _internal_func 方法:
from demo_module import *
external_func()
输出:
Python技术站
_internal_func()
输出异常信息:
NameError: "name '_internal_func' is not defined"
与通配符导入不同,常规导入不受前置单下划线命名约定的影响:
import demo_module
demo_module.external_func()
输出:
Python技术站
demo_module._internal_func()
输出:
所以我们在工作中最好遵循 PEP 8的建议,尽量避免使用通配符导入模块。
Python 后置下划线var_
有时候,某个变量最合适的名称已被Python中的关键字所占用,比如 class、def、for等名称都不能用作变量名。那么这时候,我们可以追加一个下划线来绕过命名冲突。
class = 'class-name'
print(class)
输出:SyntaxError: invalid syntax
。
class_ = 'class-name'
print(class_)
输出:class-name
。
总之,我们可以用一个后置单下划线来避免与Python关键字的命名冲突。PEP 8定义并解释了这个约定。
前置双下划线:__var
上文我们介绍的命名模式只有约定的意义,但使用双下划线开头的属性、变量或方法就不同了。
双下划线前缀的代表的含义是:此属性不允许被子类重写。
但Python作为解释型语言,并没有某个关键字为父类属性做这种限制,解释器也无法分辨这种情况,怎么办呢?
很简单,Python解释器使用了名称改写(name mangling)的方式,改写了父类属性的名称,从而避免子类中出现命名冲突。
下面用代码实例来检验一下:
class Site():
def __init__(self):
self.name = 'Python技术站'
self._domain = 'www.pythonjishu.com'
self.__tech = 'python'
t = Site()
#输出__tech属性
print(t.__tech)
输出结果为:
AttributeError: 'Site' object has no attribute '__tech'
我们发现对象t根本没有__tech的属性所以报错了,这是什么原因呢?
其实是因为Python解释器改写了__tech的变量名。
我们使用内置函数dir()看看t的属性:
['_Sitetech', 'class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'getstate', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref__', '_domain', 'name']
我们发现__tech属性被改写成了_Site__tech,也就是在前面增加了“_类名”。
输出看一看:
print(t._Site__tech)
输出:
python
通过这种方式,可以成功避免子类覆盖父类的属性。因为子类如果也定义一个 __tech 属性时,子类会将其改写为 _子类名_tech,而父类的_Site_tech属性还会保留。如下:
class ExtendedTest(Site):
def __init__(self):
super().__init__()
self.__tech = 'AI'
t2=ExtendedTest()
print(dir(t2))
输出结果为:
['_ExtendedTesttech', '_Sitetech', 'class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'getstate', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', '__reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref__', '_domain', 'name']
可以看到,t2将 tech 属性改为了 _ExtendedTest__tech,,并且保留了 _Sitetech 的父类属性。
Python 前后双下划线:var
与前置双下划线不同,名字前后都使用双下划线,不会发生名称的改写。
一般来说,前后双下划线的名称主要由Python官方使用,比如像init 这样的构造函数,让对象可调用的 call 函数等。
对于程序员来说,应当尽量避免在自己的程序中使用以双下划线开头和结尾的名称,以避免与未来Python官方名称发生冲突。
Python 单下划线_var
按照约定,单下划线作为名称,用于表示变量是临时的或者不重要的。
比如,在for循环中,就可以使用_来表示它只是一个临时值:
for _ in range(10)
print('Hello!')
在解包表达式中还可使用单下划线表示一个“被弃用”的变量。同样,这个含义也只是一个约定,不会影响任何程序。
举例如下:在以下代码中,将元组解包为单独的变量,但其中只关注color和mileage字段的值,可是为了执行解包表达式就必须为元组中的所有值都分配变量,此时_用作占位符变量:
car = ('red', 'auto', 18, 6988.4)
#_表示弃用的、不关心的变量
color, _, _, mileage = car
print(color)
总结
下划线分类 | 作用 |
---|---|
前置单下划线_var | 命名约定,用来表示该名称仅在内部使用。一般对Python解释器没有特殊含义(通配符导入除外),只能作为对程序员的提示。 |
后置单下划线var_ | 命名约定,用于避免与Python关键字发生命名冲突。 |
前置双下划线__var | 在类环境中使用时会触发名称改写,对Python解释器有特殊含义。 |
前后双下划线var | 表示由Python语言定义的特殊方法。在自定义的属性中要避免使用这种命名方式。 |
单下划线_ | 有时用作临时或无意义变量的名称(“不关心”)。此外还能表示Python REPL会话中上一个表达式的结果。 |
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python中下划线“_”都有什么含义? - Python技术站
评论列表(1条)
[…] 以双下划綫作为开头和结尾的标识符(如init),是Python专用的标识符,每一种都代表不同的含义。关于下划线的使用请参阅:Python中下划线“_”都有什么含义? […]