不知道这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中map和列表推导效率比较实例分析
Jun 17 Python
深入解析Python编程中JSON模块的使用
Oct 15 Python
Python实现代码统计工具(终极篇)
Jul 04 Python
解决出现Incorrect integer value: '' for column 'id' at row 1的问题
Oct 29 Python
Python实现多级目录压缩与解压文件的方法
Sep 01 Python
pygame游戏之旅 python和pygame安装教程
Nov 20 Python
Python判断一个list中是否包含另一个list全部元素的方法分析
Dec 24 Python
django页面跳转问题及注意事项
Jul 18 Python
python opencv将表格图片按照表格框线分割和识别
Oct 30 Python
python制作朋友圈九宫格图片
Nov 03 Python
python单向循环链表原理与实现方法示例
Dec 03 Python
pytorch程序异常后删除占用的显存操作
Jan 13 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写的带缓存数据功能的mysqli类
2012/09/06 PHP
基于curl数据采集之单页面采集函数get_html的使用
2013/04/28 PHP
深入Apache与Nginx的优缺点比较详解
2013/06/17 PHP
php简单备份与还原MySql的方法
2016/05/09 PHP
php的laravel框架快速集成微信登录的方法
2016/12/12 PHP
php实例化一个类的具体方法
2019/09/19 PHP
js宝典学习笔记(上)
2007/01/10 Javascript
js面向对象设计用{}好还是function(){}好(构造函数)
2011/10/23 Javascript
js使用eval解析json(js中使用json)
2014/01/17 Javascript
处理文本部分内容的TextRange对象应用实例
2014/07/29 Javascript
js计算任意值之间随机数的方法
2015/01/16 Javascript
JavaScript判断对象是否为数组
2015/12/22 Javascript
jQuery禁用键盘后退屏蔽F5刷新及禁用右键单击
2016/01/22 Javascript
BootStrap与validator 使用笔记(JAVA SpringMVC实现)
2016/09/21 Javascript
JavaScript mixin实现多继承的方法详解
2017/03/30 Javascript
详解vue 模版组件的三种用法
2017/07/21 Javascript
vue数组对象排序的实现代码
2018/06/20 Javascript
详解webpack-dev-server使用方法
2018/09/14 Javascript
详解vue-router的导航钩子(导航守卫)
2020/11/02 Javascript
Python实现windows下模拟按键和鼠标点击的方法
2015/03/13 Python
浅谈五大Python Web框架
2017/03/20 Python
详解django自定义中间件处理
2018/11/21 Python
Python变量类型知识点总结
2019/02/18 Python
VSCode中自动为Python文件添加头部注释
2019/11/14 Python
使用Python测试Ping主机IP和某端口是否开放的实例
2019/12/17 Python
python pyecharts 实现一个文件绘制多张图
2020/05/13 Python
Django REST Swagger实现指定api参数
2020/07/07 Python
Python实现邮件发送的详细设置方法(遇到问题)
2021/01/18 Python
利用CSS3实现平移动画效果示例代码
2016/10/12 HTML / CSS
HTML5 自动聚焦(autofocus)属性使用介绍
2013/08/07 HTML / CSS
VICHY薇姿英国官网:全球专业敏感肌护肤领先品牌
2017/07/04 全球购物
美国职棒大联盟的官方手套、球和头盔:Rawlings
2020/02/15 全球购物
出纳岗位职责范本
2013/12/01 职场文书
2015年设计师个人工作总结
2015/04/25 职场文书
2016年全国助残日活动总结
2016/04/01 职场文书
golang用type-switch判断interface的实际存储类型
2022/04/14 Golang