为什么Python中有各种各样的“_”下划线?分别有什么用?
刚开始学Python的你一定很疑惑 , 为什么Python里会出现各种各样的下划线 “_” , 而且位置都不相同 , 有时候在名称后面 , 有时候在前面 , 有时候还会在数字中间......这些下划线都分别代表了什么意思?本文就给大家普及普及 。
文章插图
在本文中 , 我们将介绍 Python 中 _ 字符的不同用法 。 就像 Python 中的许多其他内容一样 , 我们会看到 “_” 的不同用法主要是惯例问题 。 这里我们将介绍的五种不同情况:
- 单下划线(例如 _)
- 名称前加一个下划线(例如 _total)
- 名称后加一个下划线(例如 total_)
- 数字文字中的单个下划线(例如 100_000)
- 名称前加上双下划线(例如 __total)
- 名称前后加双下划线(例如 __init__)
【为什么Python中有各种各样的“_”下划线?分别有什么用?】1.在解析程序中
_名称指向交互式解释器会话中 , 最后执行的语句结果 。 这首先是由标准CPython解释器完成的 , 其他解析器也紧随其后 。
>>> _Traceback (most recent call last):File "", line 1, in NameError: name '_' is not defined>>> 42>>> _42>>> 'alright!' if _ else ':(''alright!'>>> _'alright!'
2.作为名称这与上一点有些关联 , _ 用作一次性的名称 。 这为了让阅读代码的人知道 , 这里分配了某个名称 , 但是不打算使用 。 例如 , 你可能对循环计数器的实际值不感兴趣:
n = 42for _ in range(n):do_something()
3.i18n我们可以看到 _ 还可以用作函数 。 在这种情况下 , 它通常用于执行国际化和本地化字符串转换查找的函数的名称 。 这似乎源于并遵循 C 语言的相关规则 。 如在Django文档中所见:
from django.http import HttpResponsefrom django.utils.translation import gettext as _def my_view(request):output = _("Welcome to my site.")return HttpResponse(output)
第二个和第三个用法可能会发生冲突 , 因此 , 在任何还将 _ 用作 i18n 查找和翻译的代码块中 , 都应避免使用 _ 作为一次性使用的名称 。二.名称前加单下划线(例如_total)名称前的单个下划线用于指定程序员将名称视为“私有” 。 这可以视为一种约定 , 方便阅读代码的人知道以 _ 开头的名称供内部使用 。正如Python文档所述:
带有下划线的名称(例如 _spam)应被视为 API 的非公开部分(无论是函数、方法还是数据成员) 。 它应被视为实现细节 , 如有更改 , 恕不另行通知 。
*之所以说是一种约定 , 是因为它实际上对解析程序而言有着某种意义;如果我们从
三. 名称后的单下划线(例如 total_)名称后面的单个下划线用于避免名称遮盖另一个名称 , 当然是惯例 。 例如 , 如果你想命名某种格式 , 为了避免掩盖 Python 的内置格式 , 你可以将其命名为 format_ 。
四. 数字字面中的单下划线(例如 100_000)PEP 515 指数建议扩展 Python 的语法 , 以便下划线可以用作整体、浮点和复杂数字文本中数字分组的可视分隔符 , 理由是:
这是其他现代语言的常见特征 , 可以帮助提高较长的文字或文本的可读性 , 其值应清楚地分隔成部分 , 如字节或十六进制表示法中的单词 。
因此 , 我们可以执行以下操作::
# 十进制数按千分组amount = 10_000_000.0# 按字对十六进制地址进行分组addr = 0xCAFE_F00D# 用二进制文字将位分组为半字节flags = 0b_0011_1111_0100_1110#相同 , 用于字符串转换flags = int('0b_1111_0000', 2)
五. 姓名前的双下划线(例如__total)在名称(特别是方法名称)前使用双下划线(__)不是约定 , 只是对解析程序有特殊的意义 。 Python 管理这些名称 , 它用于避免名称与子类定义的名称冲突 。 正如Python文档所指出的那样 , 任何形式为__spam 的标识符(至少两个前导下划线 , 并且最多一个尾随下划线)在文本上均被 _classname__spam替换 , 其中 classname 是当前类名 , 其中前导下划线被去除 。以以下示例为例:
>>> class A(object):...def _internal_use(self):...pass...def __method_name(self):...pass... >>> dir(A())['_A__method_name', ..., '_internal_use']
如上所示 , _internal_use 不变 , 但是 __method_name 被改成 _ClassName__method_name 。现在 , 如果你创建 A 的子类 , 比如说 B(坏、坏名字) , 那么你将无法轻易覆盖 A 的__method_name:
- 看不上|为什么还有用户看不上华为Mate40系列来看看内行人怎么说
- 制药领域|为什么AI制药这么火,为什么是现在?
- 手机壳里头|为什么要在手机壳里面夹钱?10个有9个不懂,我才知道大有讲究
- 短视频|全球最火APP?抖音爆火背后离不开这几剂“猛药”为什么抖音能够这么火?
- 电商快递|包邮不香吗,为什么还有人加49元让小哥穿西装专车送快递?
- 团队|为什么项目管理非常重要?
- 猫腻|为什么拼多多上商品价格那么便宜还包邮?有什么猫腻?看完明白了
- 刷机|前几年满大街的“刷机”服务去哪里了,为什么大家都不爱刷机了?
- 手机|便宜没好货!为什么二手iPhone很便宜,这些手机都来自哪儿?
- 中国|相对论Vol.48丨一个“歪果仁”,为什么要在海外电商平台直播带中国货