不知道这5种下划线的含义,你就不算真的会Python!


Posted in Python onOctober 09, 2018

什么是 Python? Python 之父 Guido van Rossum 说:Python是一种高级程序语言,其核心设计哲学是代码可读性和语法,能够让程序员用很少的代码来表达自己的想法。

对于我来说,学习 Python 的首要原因是,Python 是一种可以优雅编程的语言。它能够简单自然地写出代码和实现我的想法。

另一个原因是我们可以将 Python 用在很多地方:人工智能、数据科学、Web 开发和机器学习等都可以使用 Python 来开发。

国庆期间后台有小伙伴留言问我:“Python变量和方法名称中单下划线和双下划线的含义是什么?”我想一些初学者或者经验尚浅的朋友一定也会有这个疑问,所以今天我就来跟大家聊聊Python中这个很重要的“下划线”!

不知道这5种下划线的含义,你就不算真的会Python!

单下划线和双下划线在Python变量和方法名称中都各有其含义。有一些含义仅仅是依照约定,被视作是对程序员的提示 - 而有一些含义是由Python解释器严格执行的。

那么,下面就为大家介绍一下Python中单下划线和双下划线("dunder")的各种含义和命名约定,名称修饰(name mangling)的工作原理,以及它如何影响你自己的Python类。

下面将讨论以下五种下划线模式和命名约定,以及它们如何影响Python程序的行为:

单前导下划线:_var

单末尾下划线:var_

双前导下划线:__var

双前导和末尾下划线:__var__

单下划线:_

1、单前导下划线 _var

程序员使用名称前的单下划线,用于指定该名称属性为“私有”。这有点类似于惯例,为了使其他人(或你自己)使用这些代码时将会知道以“_”开头的名称只供内部使用。正如Python文档中所述:

以下划线“_”为前缀的名称(如_spam)应该被视为API中非公开的部分(不管是函数、方法还是数据成员)。此时,应该将它们看作是一种实现细节,在修改它们时无需对外部通知。

正如上面所说,这确实类似一种惯例,因为它对解释器来说确实有一定的意义,如果你写了代码“from <模块/包名> import *”,那么以“_”开头的名称都不会被导入,除非模块或包中的“__all__”列表显式地包含了它们。

看看下面的例子:

class Test:
def __init__(self):
self.foo = 11
self._bar = 23

如果你实例化此类,并尝试访问在__init__构造函数中定义的foo和_bar属性,会发生什么情况? 让我们来看看:

>>> t = Test()
>>> t.foo
11
>>> t._bar
23

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

这是因为Python中的单个下划线前缀仅仅是一个约定 - 至少相对于变量和方法名而言。

但是,前导下划线的确会影响从模块中导入名称的方式。

假设你在一个名为my_module的模块中有以下代码:

# This is my_module.py:
def external_func():
return 23
def _internal_func():
return 42

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

>>> from my_module import *
>>> external_func()
23
>>> _internal_func()
NameError: "name '_internal_func' is not defined"

顺便说一下,应该避免通配符导入,因为它们使名称空间中存在哪些名称不清楚。 为了清楚起见,坚持常规导入更好。

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

>>> import my_module
>>> my_module.external_func()
23
>>> my_module._internal_func()
42

我们知道这一点可能有点令人困惑。 如果你遵循PEP 8推荐,避免通配符导入,那么你真正需要记住的只有这个:

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

2、单末尾下划线 var_

有时候,一个变量的最合适的名称已经被一个关键字所占用。 因此,像class或def这样的名称不能用作Python中的变量名称。 在这种情况下,你可以附加一个下划线来解决命名冲突:

>>> def make_object(name, class):
SyntaxError: "invalid syntax"
>>> def make_object(name, class_):
... pass

总之,单个末尾下划线(后缀)是一个约定,用来避免与Python关键字产生命名冲突。 PEP 8解释了这个约定。

3、双前导下划线 __var

名称(具体为一个方法名)前双下划线(__)的用法并不是一种惯例,对解释器来说它有特定的意义。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”。

>>> class B(A):
... def __method_name(self):
... pass
...
>>> dir(B())

['_A__method_name', '_B__method_name', ..., '_internal_use']

这里的功能几乎和Java中的final方法和C++类中标准方法(非虚方法)一样。

4、双前导和双末尾下划线 _var_

也许令人惊讶的是,如果一个名字同时以双下划线开始和结束,则不会应用名称修饰。 由双下划线前缀和后缀包围的变量不会被Python解释器修改:

class PrefixPostfixTest:
def __init__(self):
self.__bam__ = 42
>>> PrefixPostfixTest().__bam__
42

但是,Python保留了有双前导和双末尾下划线的名称,用于特殊用途。 这样的例子有,__init__对象构造函数,或__call__ --- 它使得一个对象可以被调用。

这些dunder方法通常被称为神奇方法 - 但Python社区中的许多人都不喜欢这种方法。

最好避免在自己的程序中使用以双下划线(“dunders”)开头和结尾的名称,以避免与将来Python语言的变化产生冲突。

5、单下划线 _

通常情况下,会在以下3种场景中使用:

1、在解释器中:在这种情况下,“_”代表交互式解释器会话中上一条执行的语句的结果。这种用法首先被标准CPython解释器采用,然后其他类型的解释器也先后采用。

>>> _ Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_' is not defined
>>> 42
>>> _
42
>>> 'alright!' if _ else ':('
'alright!'
>>> _
'alright!'

2、作为一个名称:这与上面一点稍微有些联系,此时“_”作为临时性的名称使用。这样,当其他人阅读你的代码时将会知道,你分配了一个特定的名称,但是并不会在后面再次用到该名称。例如,下面的例子中,你可能对循环计数中的实际值并不感兴趣,此时就可以使用“_”。

n = 42
for _ in range(n):
do_something()

3、国际化:也许你也曾看到”_“会被作为一个函数来使用。这种情况下,它通常用于实现国际化和本地化字符串之间翻译查找的函数名称,这似乎源自并遵循相应的C约定。

例如,在Django文档“转换”章节中,你将能看到如下代码:

from django.utils.translation import ugettext as _
from django.http import HttpResponse
def my_view(request):
output = _("Welcome to my site.")
return HttpResponse(output)

可以发现,场景二和场景三中的使用方法可能会相互冲突,所以我们需要避免在使用“_”作为国际化查找转换功能的代码块中同时使用“_”作为临时名称。

总结:

Python下划线命名模式 - 小结

以下是一个简短的小结,即“速查表”,罗列了本文中谈到的五种Python下划线模式的含义:

不知道这5种下划线的含义,你就不算真的会Python!

以上所述是小编给大家介绍的不知道这5种下划线的含义,你就不算真的会Python!,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
Python编程中用close()方法关闭文件的教程
May 24 Python
Python中的anydbm模版和shelve模版使用指南
Jul 09 Python
python实现报表自动化详解
Nov 16 Python
python面向对象入门教程之从代码复用开始(一)
Dec 11 Python
详解js文件通过python访问数据库方法
Mar 03 Python
详解Django定时任务模块设计与实践
Jul 24 Python
python实现局域网内实时通信代码
Dec 22 Python
pytorch 实现将自己的图片数据处理成可以训练的图片类型
Jan 08 Python
python实现根据给定坐标点生成多边形mask的例子
Feb 18 Python
Pandas读取csv时如何设置列名
Jun 02 Python
python 使用建议与技巧分享(四)
Aug 18 Python
用OpenCV进行年龄和性别检测的实现示例
Jan 29 Python
详解利用django中间件django.middleware.csrf.CsrfViewMiddleware防止csrf攻击
Oct 09 #Python
详解如何将python3.6软件的py文件打包成exe程序
Oct 09 #Python
让代码变得更易维护的7个Python库
Oct 09 #Python
windows下cx_Freeze生成Python可执行程序的详细步骤
Oct 09 #Python
Python打包方法Pyinstaller的使用
Oct 09 #Python
Python如何发布程序的详细教程
Oct 09 #Python
python如何发布自已pip项目的方法步骤
Oct 09 #Python
You might like
谈谈PHP语法(4)
2006/10/09 PHP
ubuntu 编译安装php 5.3.3+memcache的方法
2010/08/05 PHP
table标签的结构与合并单元格的实现方法
2013/07/24 PHP
php使用fopen创建utf8编码文件的方法
2014/10/31 PHP
PHP文件缓存类示例分享
2015/01/30 PHP
php计算函数执行时间的方法
2015/03/20 PHP
PHP编写文件多服务器同步程序
2016/07/02 PHP
PHP socket 模拟POST 请求实例代码
2016/07/18 PHP
浅谈PHP实现大流量下抢购方案
2017/12/15 PHP
PHP7.1实现的AES与RSA加密操作示例
2018/06/15 PHP
PHP mongodb操作类定义与用法示例【适合mongodb2.x和mongodb3.x】
2018/06/16 PHP
Javascript中的数学函数集合
2007/05/08 Javascript
javascript hasFocus使用实例
2010/06/29 Javascript
jquery动态增加删除表格行的小例子
2013/11/14 Javascript
JavaScript实现弹出子窗口并传值给父窗口
2014/12/18 Javascript
浅谈JavaScript function函数种类
2014/12/29 Javascript
js判断移动端是否安装某款app的多种方法
2015/12/18 Javascript
AngularJS中实现用户访问的身份认证和表单验证功能
2016/04/21 Javascript
Vue数据驱动模拟实现1
2017/01/11 Javascript
vue.js使用v-pre与v-html输出HTML操作示例
2018/07/07 Javascript
python with statement 进行文件操作指南
2014/08/22 Python
在Python中使用zlib模块进行数据压缩的教程
2015/06/26 Python
Windows下的Python 3.6.1的下载与安装图文详解(适合32位和64位)
2018/02/21 Python
python实现微信自动回复功能
2018/04/11 Python
使用批处理脚本自动生成并上传NuGet包(操作方法)
2019/11/19 Python
Python中类似于jquery的pyquery库用法分析
2019/12/02 Python
Python 解析pymysql模块操作数据库的方法
2020/02/18 Python
python在协程中增加任务实例操作
2021/02/28 Python
浅谈html5增强的页面元素
2016/06/14 HTML / CSS
Myprotein芬兰官网:欧洲第一运动营养品牌
2019/05/05 全球购物
应届生求职信范文
2014/05/26 职场文书
市级绿色学校申报材料
2014/08/25 职场文书
研修心得体会
2014/09/04 职场文书
复兴之路纪录片观后感
2015/06/02 职场文书
篮球赛闭幕式主持词
2015/07/03 职场文书
Java Lambda表达式常用的函数式接口
2022/04/07 Java/Android