在Python的变量名和方法名中,单下划线和双下划线都有各自的含义,有的仅仅是作为约定,用于提示开发人员,而有的则对Python解释器有特殊含义。

你可能有些疑惑,在Python中变量名和方法名中的单下划线、双下划线到底有什么含义?下面我们就来看看下面五种下划线模式和命名约定,以及它们各自如何影响Python程序的行为:

  • 前置单下划线:_var
  • 后置单下划线:var_
  • 前置双下划线:__var
  • 前后双下划线:__var__
  • 单下划线:_

前置单下划线:_var

当涉及变量名和方法名时,前置单下划线只有约定含义。它对于程序员而言是一种提示,Python社区约定好单下划线表达的是某种意思,其本身并不会影响程序的行为。

前置单下划线的意思是提示其他程序员,以单下划线开头的变量或方法只在内部使用。PEP 8中定义了这个约定(PEP 8是最常用的Python代码风格指南8),不过,这个约定对Python解释器并没有特殊含义,与Java不同,Python在“私有”和“公共”之间并没有很强的区别。

来看下面的Student类例子:

class Student:def __init__(self):self.name = "Mark"self._age = 18

如果实例化这个类并尝试访问在__init__构造函数中定义的name和_age属性,会发生什么情况?

可以看到_age前面的单下划线并没有阻止我们访问变量的值,这是因为Python中的前置单下划线只是一个公认的约定,至少在涉及变量名和方法名时是这样的。但是前置下划线会影响从模块中导入名称的方式。假设在一个名为common.py的模块中有如下代码:

def func1():return "func1"def _func2():return "func2"

现在,如果使用 from common import * 这种方式导入所有名称,Python不会导入带有前置单下划线的名称,除非在模块中定义了__all__列表覆盖了这个行为:

顺便说一下,我们应尽量避免使用*号导入,因为这样就不清楚当前名称空间中存在哪些名称了,为了清楚起见,最好坚持使用常规导入方法,与*号导入不同,常规导入不受前置单下划线命名约定的影响:

后置单下划线:var_

有时,当某个变量的名称已被Python语言中的关键字占用,如class、def等的名称不能用作Python中的变量名,在这种情况下可以追加一个下划线来绕过命名冲突:

用一个后置单下划线来避免与Python关键字的命名冲突是一个约定。PEP 8定义并解释了这个约定。

前置双下划线:__var

前面的两种下划线模式只有约定的意义,但使用以双下划线开头的Python类属性(变量和方法)就不一样了,双下划线前缀会让Python解释器重写属性名称,以避免子类中的命名冲突,这也称为名称改写,即解释器会更改变量的名称,以便在稍后扩展这个类时避免命名冲突,下面用代码示例来实验一下:

class Student:def __init__(self):self.name = "Mark"self._age = 18self.__gender = "男"if __name__ == "__main__":student = Student()print(dir(student))

上图中我们用内置的dir()函数看这个对象的属性:该函数返回了一个包含对象属性的列表,在这个列表中尝试寻找之前的变量名称name、_age和__gender,你会发现一些有趣的变化,首先,self.name变量没有改动,在属性列表中显示为name,接着,self._age也一样,在类中显示为_age,在这种情况下前置下划线仅仅是一个约定,是对程序员的一个提示,然而self.__gender就不一样了,在该列表中找不到__gender这个变量,仔细观察就会看到,这个对象上有一个名为_Student__gender的属性,这就是Python解释器应用名称改写之后的名称,是为了防止子类覆盖这些变量。

名称改写也适用于方法名,会影响在类环境中所有以双下划线开头的名称。

前后双下划线:__var__

如果名字前后都使用双下划线,则不会发生名称改写,前后由双下划线包围的变量不受Python解释器的影响:

class Student:def __init__(self):self.name = "Mark"self._age = 18self.__gender = "男"self.__score__ = 99if __name__ == "__main__":student = Student()print(dir(student))print(f"score = {student.__score__}")

但是前后双下划线的名称在Python中有特殊用途,像__init__这样的对象构造函数,用来让对象可调用的__call__函数,都遵循这条规则。

这些双下划线方法通常被称为魔法方法,双下划线方法是Python的核心功能,应根据需要使用,但就命名约定而言,最好避免在自己的程序中使用以双下划线开头和结尾的名称,以避免与Python语言的未来变更发生冲突。

单下划线:_

按照约定,单下划线有时用作名称,来表示变量是临时的或弃用的,例如下面的循环中并不需要访问运行的索引,那么可以使用_来表示它只是一个临时值:

if __name__ == "__main__":for _ in range(5):print("hello world!")

在解包表达式中还可使用单下划线表示一个弃用的变量来忽略特定的值,同样,这个含义只是一个约定,不会触发Python解析器中的任何特殊行为,单下划线只是一个有效的变量名,偶尔用于该目的。

下面的代码示例中,我将元组解包为单独的变量,但其中只关注name和score字段的值。可是为了执行解包表达式,我们就必须为元组中的所有值都分配变量,此时 _ 用作占位符变量:

if __name__ == "__main__":student = ("mark", 19, "男", "99分")name, _, _, score = studentprint(f"name = {name}, score = {score}, _ = {_}")

除了用作临时变量之外,_在大多数Python REPL中是一个特殊变量,表示由解释器计算的上一个表达式的结果,如果正在使用解释器会话,用下划线可以方便地获取先前计算的结果:

如果正在实时构建对象,有单下划线的话不用事先指定名称就能与之交互:

总结:

  • 前置单下划线_var:命名约定,用来表示该名称仅在内部使用。一般对Python解释器没有特殊含义(*号导入除外),只能作为对程序员的提示。
  • 后置单下划线var_:命名约定,用于避免与Python关键字发生命名冲突。
  • 前置双下划线__var:在类环境中使用时会触发名称改写,对Python解释器有特殊含义。
  • 前后双下划线__var__:表示由Python语言定义的特殊方法。在自定义的属性中要避免使用这种命名方式。
  • 单下划线_:有时用作临时或弃用变量的名称,此外还能表示Python REPL会话中上一个表达式的结果。

python变量下划线开头_一日一技:python中下划线在不同位置的作用相关推荐

  1. python中不被定义_一日一技:在Python中双下划线私有方法不能被调用的原理

    一日一技:在Python中双下划线私有方法不能被调用的原理 在使用Python编写面向对象的代码时,我们会常常使用"继承"这种开发方式.例如下面这一段代码: class Info: ...

  2. python变量无需创建赋值_阿博的Python之路-变量

    之前阿博分享了Python的运算符,在它的后面开始学习变量相关的知识.在这里要给小伙伴们分享Python的变量. 注意:小编的编码环境是Python 3. 什么是变量 Python变量是记录事物变化状 ...

  3. python归并排序理解不了_一日一技:如何更好地理解归并排序?

    一日一技:如何更好地理解归并排序? 摄影:产品经理 厨师:kingname 请确保你已经看了我昨天的公众号文章.昨天的内容是今天的基础. 一日一技:在 Python 里面如何合并多个有序列表并使得结果 ...

  4. java能下划线开头_为什么Java7开始在数字中使用下划线

    JDK1.7的发布已经介绍了一些有用的特征,尽管大部分都是一些语法糖,但仍然极大地提高了代码的可读性和质量.其中的一个特征是介绍字面常量数字的下划线.从Java7开始,你就可以在你的Java代码里把长 ...

  5. python变量类型之间转换_【Python】Python 变量类型(变量赋值,数据类型,数据转换)...

    目录 Python 变量类型 变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间.基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中.因此,变量可以指定不同的数 ...

  6. python线程监控配置文件_一日一技:Python多线程的事件监控

    一日一技:Python多线程的事件监控 设想这样一个场景: 你创建了10个子线程,每个子线程分别爬一个网站,一开始所有子线程都是阻塞等待.一旦某个事件发生:例如有人在网页上点了一个按钮,或者某人在命令 ...

  7. python模型预测结果 取整_一日一技:Python里面的//并不是做了除法以后取整

    一日一技:Python里面的//并不是做了除法以后取整 在Python 3里面,我们做除法的时候会遇到 a/b 和 a//b两种写法: >>> 10 / 3 3.3333333333 ...

  8. python环境下数据操作_数据分析环境搭建和Python基础知识

    搭建数据分析环境主要包括使用anaconda管理包和环境:使用Jupyter notebook将说明文本.数学方程.代码和可视化内容全部组合到一个易于共享的文档中.Python基础知识包括关键点(数据 ...

  9. python中的断言是什么意思_一日一技:python中的断言

    一.使用python中的断言来自动检测python程序中的错误,让程序更加可靠且更易于调试 从根本上来说,python中的断言语句是一种调试工具,用来测试某个断言条件,如果断言条件为True,则程序将 ...

最新文章

  1. java object finalize_Java Object finalize() 方法
  2. (一) 关于配置travis-ci持续集成python pytest测试的相关记录
  3. javascript DOM(08-21)
  4. 信息学奥赛一本通(1013:温度表达转化)
  5. 支持向量机(SVM)复习总结
  6. 封杀抖音,微博在紧张什么?
  7. 阿里花17.7亿 买的才不是ofo一堆没用的单车
  8. linux是用于汇编语言,深入理解程序设计:使用Linux汇编语言
  9. Software - ASCII码表
  10. 你不专业并且自以为是,所以被坑
  11. JavaScript强化教程——AngularJS 表达式
  12. pycharm汉化包
  13. 集成电路总设计(Ⅴ)
  14. Android模拟器 使用 Fiddler抓包
  15. [C++]求模与求余运算
  16. HTML巩固练习之字体样式
  17. iPhone模拟器部分操作
  18. 工作三四年,如果你也迷茫。
  19. signal 11 linux,signal 11 (SIGSEGV)错误排查
  20. 2021年危险化学品经营单位安全管理人员考试及危险化学品经营单位安全管理人员试题及解析

热门文章

  1. IBASE category 01 component hierarchy
  2. 一个程序员必须学会的Github使用技巧
  3. html3d旋转发光立方体,纯css3实现的3D立体动态旋转立方体特效
  4. js 字符串减去字符串_js关于字符串、条件语句和自加和自减
  5. 姓名性别电话邮箱html表单,HTML form标签语法、属性、规范和示例详细说明-立地货...
  6. c语言打开外部doc文件,C语言-内部函和外部函数.doc
  7. springboot使用imageio返回图片_SpringBoot 二维码生成(复制即用)
  8. java开发学不会_JAVA学不会,快期末了,怎么办?
  9. 力扣Java编译器_力扣--设计单链表
  10. python命令行输入参数_Python3.x那些事儿:[3]命令行参数传递