在python中,经常会看到_x
、__x
、__xx__
这样的变量,那么这些变量到底是什么?实际上单下划线、双下划线前缀,是python中的一种约定。具体来说,
-
单下划线:表示"内部使用",是非强制性的私有属性,模块(文件)中单下划线中的成员在这个模块被导入时,不会被导入。
-
双下划线:会触发名称改写,也就是说一旦定义了双下划线的成员,在访问时必须以python编译后名称去访问。
-
前后双下划线:保留给python内部使用,是一种python的语言协议,也叫做魔术方法。
单下划线_xx
:protected
- 非强制的私有属性,类似于告诉别人"别随便使用,这是内部细节",但是还是允许使用,比如:
python
class A:
def __init__(self):
self._hidden = 42
a = A()
print(a._hidden)
#-------
42 #当然可以访问,但不推荐
- 某个模块(文件)中带有下划线开头的成员,在这个模块被导入时,不会被导入。双下划线、前后双下划线也不会被导入
python
# module_1.py
a = 1
_b = 2
def foo():
return "foo"
def _bar():
return "_bar"
# module_2.py
from module_1 import *
print(a) # ✅ 输出 1
print(foo()) # ✅ 输出 "foo"
print(_b) # ❌ 报错: NameError
print(_bar()) # ❌ 报错: NameError
#------
# NameError: name '_b' is not defined
- 在
from module_1 import *
时,Python 会导入module_1
里所有的"公共符号",如果名字以 单下划线_
开头 ,Python 会认为它是"内部用的",就不会被import *
导入 - 但是要注意,虽然不会默认导入,但是还是可以显式的来进行导入
python
# module_1.py
a = 1
_b = 2
def foo():
return "foo"
def _bar():
return "_bar"
# module_2.py
from module_1 import *
from module_1 import _b,_bar
print(a) # ✅ 输出 1
print(foo()) # ✅ 输出 "foo"
print(_b) # ✅ 输出 2
print(_bar()) # ✅ 输出 "_bar"
双下划线__XX
:private
- 会触发名称改写(name mangling),python在编译的时候,会把这个成员的名字
__XXX
改成_类名__XXX
,只有访问_类名__XXX
才可以访问这个成员 。
python
class A:
def __init__(self):
self.__secret = 99 # 会被改写为 _A__secret
a = A()
print(a.__secret) # 报错:AttributeError
print(a._A__secret) # 99
- 经常用来实现类的私有属性,防止外部或子类直接访问
前后双下划线__XX__
:double underscore methods(魔术方法)
- Python 数据模型规定的特殊方法或属性,是和解释器/运行时协议挂钩的"钩子"。
python
class A:
def __str__(self):
return "I am A"
a = A()
print(str(a)) # I am A