Python中_x,__x和__x__的区别

Python中x,\_x和__x__的区别很多人不甚了解,本文将做一个全面介绍。

假设有一个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class EncryptedFile():

"""
加密文件类
"""

def __init__(self, name, content):
self.name = name
self.content = content

def get_encrypted_content(self):
return self._encrypt()

def _encrypt(self):
# encrypt the file content here

上述代码中出现了__init___encrypt两个方法,__init__是一个Python的魔术方法,它是内建的方法,这个方法负责初始化Python类的实例,还有很多魔术方法,比如__len____new__等等。_encrypt是一个私有的方法,实际上Python并没有Java那种真正私有的方法,Python在规范中说明了私有方法或私有变量以单个_开头。

再看一个类继承的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A():
def __init__(self, name):
self.__name = "a_name"

class B():
def __init__(self, name):
self.__name = "b_name"

class C(A, B):
def __init__(self, name):
A.__init__(self, name)
B.__init__(self, name)
self.__name = name

c = C("c_name")
print(c.__dict__) # {'_A__name': 'a_name', '_B__name': 'b_name', '_C__name': 'c_name'}
print(c.__name) # AttributeError: 'C' object has no attribute '__name'

上面代码中定义了两个类A和B,且类C多继承于A和B,A、B和C三个类都有一个同名的实例变量__name。由于在继承体系中可能存在同名的变量,因此需要加以区分:我们在代码中引用c.__name的时候会报错。注意观察可以发现,在类继承中,以__开头,至多一个_结尾的变量在子类中会被改写为_{class_name}__{variable_name}。在上例中,类A的__name在子类C中被改写为_A__name,类B的__name在子类C中被改写为_B__name,类C的__name在子类C中被改写为_C__name。这样做可以有效避免类继承的情况下同名变量无法被区分的情况。

总结一下:

__x__ _x __x或者__x_
含义 Python内建魔术方法或魔术变量 约定的私有变量命名规范 为了避免在继承中命名冲突而起的变量名,将被改写为_{class_name}__{variable_name}