单下划线
单下划线开头的命名方式被常用于模块中,在一个模块中以单下划线开头的变量和方法会被默认划入模块内部范围。当使用 from my_module import * 导入时,单下划线开头的变量和方法是不会被导入的。但使用 import my_module 导入的话,仍然可以用 my_module._var 这样的形式访问属性或方法。
单下划线结尾的命名方式也存在,但是不常用,其实也不推荐用。这种命名方式的作用就是为了和 python 的一些内置关键词区分开来,假设我们想给一个变量命名为 class,但是这会跟 python 的关键词 class 冲突,所以我们只好退一步使用单下划线结尾命名,也就是 class_。
双下划线
双下划线开头和结尾的是一些 python 的“魔术”对象,如类成员的 __init__、__del__、__add__、__getitem__ 等,以及全局的__file__、__name__ 等。 python 官方推荐永远不要将这样的命名方式应用于自己的变量或函数,而是按照文档说明来使用。
双下划线开头的命名方式有实际的作用,采用这种命名的变量或方法无法直接通过 “对象名.变量名(方法名)” 这样的方式访问。
看看python官方文档中的解释:
类似”__spam”格式的任何标识符(至少有两个前导下划线,最多一个尾部下划线)在python底层都会被修改成”_classname__spam”,其中classname是当前的类名。这种修改(mangling)不会考虑标识符的语法位置,因此可以用来定义类私有实例和类变量、方法、全局变量,甚至是存储在实例中的变量。
对标识符修改(Name mangling)的说明:
名称修改旨在为类提供一种简单的方法来定义“私有”实例变量和方法,而不必担心派生类定义的实例变量,或者通过类外部的代码来修改实例变量。请注意,设计这种标识符的修改主要是为了避免一些在无意中可能造成的代码事故,避免不了那些执意要访问或者修改那些已经被视为私有的变量的行为。
开始验证:
#实现一个简单的类
class MyClass():
def __init__(self):
self._semiprivate = "Hello"
self.__superprivate = "world!"
#创建一个实例
mc = MyClass()
#查看实例mc的字典,里面存放了该实例的变量
print(mc.__dict__)
#输出:{'_semiprivate': 'Hello', '_MyClass__superprivate': 'world!'}
#可以看到Name mangling的效果了:'__superprivate'被修改为'_MyClass__superprivate'
#所以调用mc.__superprivate是肯定要出错的~
print(mc._semiprivate) #输出:Hello
print(mc._MyClass__superprivate) #输出:world!
print(mc.__superprivate)
#报错:AttributeError: 'MyClass' object has no attribute '__superprivate'
参考:stackoverflow、知乎