下划线的使用
1. 单下划线用作变量
最常见的一种使用场景是作为变量占位符,使用场景明显可以减少代码中多余变量的使用。为了方便理解,_
可以看作被丢弃的变量名称,
这样做可以让阅读你代码的人知道,这是个不会被使用的变量。
alist = [(1, 2, 3), (4, 5, 6), (7, 8, 9)] for _, _, x in alist: print(x) # 3, 6, 9
2. 单下划线前缀名称
以下划线“_”
为前缀的名称应该被视为API中非公开的部分(不管是函数、方法还是数据成员),指定该名称属性为“私有”,只能内部使用。
1)类中定义下划线开头的属性或者方法。相当于 protected 限定的变量,表示外部无法访问,子类可以继承。虽然这么定义了,但 Python 并不
会真的阻止别人访问内部名称,即如果外部想访问这个保护的变量也是可以的,所以只是一种约定。
2)模块(.py文件)中定义下划线开头的变量或者函数。这么定义的话,通过 from module import *
或 import module 这两种方式便无法将下划
线开头的变量或函数导入,
但是可以通过 from module import _var 这种指定的方式导入。
3. 单下划线后缀名称
通常用于和 Python 关键词区分开来,比如我们需要一个变量叫做 var,但 var 是 Python 的关键词,就可以以单下划线结尾写作 var_。
4. 双下划线前缀名称
Python文档指出,“__var”这种形式(至少两个前导下划线,最多一个后续下划线)的任何标识符将会被“_classname__spam”这种形式原文取代,
在这里“classname”是去掉前导下划线的当前类名。直接看个例子:
class A(object): def __init__(self): self.__private = 0 def _internal_use(self): pass def __method_name(self): pass obj = A() print(obj) # ['_A__method_name', '_A__private', '_internal_use', ...] print(obj._A__private) # 正确 print(obj.__private) # 'A' object has no attribute '__private'
可以看到 __private 和 __method_name 都被重新命名为 _A__method_name 和 _A__private。
可以看出因为双下划线开头的属性或者方法的名字被内部改掉了,于是外部访问的时候就会发生无定义的情况。
不仅外部无法访问,这种属性通过继承也是无法被覆盖的。我们来定义一个继承自A的类B。
class B(A): def __init__(self): super().__init__() self.__private = 1 # Does not override A.__private # Does not override B.__private_method() def __private_method(self): pass obj = B() print(dir(obj)) # ['_A__method_name', '_A__private', '_B__private', '_internal_use', ...]
这里,私有名称 __private 和 __private_method 被重命名为 _B__private 和_B__private_method ,这个跟父类 A 中的名称是完全不同的。
由此可见,虽然 B 继承了 '_A__method_name' 和 '_A__private',但操作原先的变量名却不是访问,而是定义。所以双下划线变量就很类似于
privated 限定的,外部和子类都无法直接访问。