Python 中 `__all__` 与 `import *` 的关系及核心用法
Python 中 __all__ 与 import * 的关系及核心用法
在 Python 模块导入中,__all__ 和 import *(星号导入)是紧密关联但完全不同的概念,前者是“模块的导出清单”,后者是“导入语法”。下面分点详细拆解:
一、__all__ 与 import * 的核心区别(是不是一回事?)
不是一回事,两者的角色和作用完全不同:
import *:是一种导入语法,作用是“批量导入模块中所有‘公开成员’”(公开成员的定义由__all__决定)。
例如from module import *,表示“导入module里的所有公开变量、函数、类”。__all__:是模块内定义的一个字符串列表,作用是“明确指定当前模块对外暴露的‘公开成员’清单”,专门用于约束import *的导入范围。
例如模块中定义__all__ = ["func1", "ClassA"],则from module import *只会导入func1和ClassA,其他未在列表中的成员不会被导入。
二、__all__ 的核心作用:约束 import * 的导入范围
__all__ 的唯一核心场景是配合 import * 使用,解决“批量导入时哪些成员该暴露”的问题。具体分两种情况:
1. 模块中定义了 __all__:import * 只导入 __all__ 列表中的成员
# 模块文件:my_module.py
__all__ = ["add", "MyClass"] # 明确公开成员清单
def add(a, b): # 在 __all__ 中,会被 import * 导入
return a + b
def _inner_func(): # 不在 __all__ 中,不会被 import * 导入(单下划线约定内部成员)
return "内部辅助函数"
class MyClass: # 在 __all__ 中,会被 import * 导入
pass
class _InnerClass: # 不在 __all__ 中,不会被 import * 导入
pass
# 外部导入代码
from my_module import *
add(1, 2) # 正常使用(已导入)
MyClass() # 正常使用(已导入)
_inner_func() # 报错:NameError(未被导入)
_InnerClass() # 报错:NameError(未被导入)
2. 模块中未定义 __all__:import * 导入“所有非单下划线开头的成员”
如果模块没有显式定义 __all__,import * 会默认导入模块中“名称不以单下划线(_)开头”的成员(遵循 Python 中“单下划线为内部成员”的约定)。
# 模块文件:my_module2.py(未定义 __all__)
def public_func(): # 非单下划线开头,会被 import * 导入
pass
def _private_func(): # 单下划线开头,不会被 import * 导入
pass
VAR = 100 # 非单下划线开头,会被 import * 导入
_inner_var = 200 # 单下划线开头,不会被 import * 导入
# 外部导入代码
from my_module2 import *
public_func() # 正常使用(已导入)
print(VAR) # 正常使用(已导入:100)
_private_func() # 报错:NameError(未被导入)
print(_inner_var)# 报错:NameError(未被导入)
三、__all__ 是不是每个模块都有?需要单独定义吗?
不是每个模块都有 __all__,__all__ 是“需要显式定义才存在的成员”,具体规则:
- 默认不存在:Python 模块不会自动生成
__all__,如果开发者不手动定义,模块的命名空间中就没有__all__这个变量。
可以通过print(__all__)在模块内部验证,未定义时会直接报错NameError: name '__all__' is not defined。 - 需手动定义:只有当开发者需要“精确控制
import *的导入范围”时(比如某些非单下划线开头的成员也想隐藏),才需要在模块顶部显式定义__all__列表。
例如:模块中有一个非单下划线的成员temp_func,但不想让import *导入,就可以通过__all__排除它:# 模块文件:my_module3.py __all__ = ["add"] # 只暴露 add,排除 temp_func def add(a, b): return a + b def temp_func(): # 非单下划线,但不在 __all__ 中,不会被 import * 导入 pass
四、关键注意点
__all__只影响import *:__all__不会限制“显式导入”(比如from module import 成员名)。即使成员不在__all__中,只要显式写出成员名,依然可以导入(但不推荐,违反模块的设计意图)。
例如:from my_module import _inner_func(语法允许,但_inner_func是内部成员,不建议外部使用)。__all__必须是字符串列表:如果定义的__all__不是列表,或列表中包含非字符串元素,会导致import *报错。
错误示例:__all__ = [add, MyClass](应该用字符串"add"、"MyClass")。- 子模块导入不影响
__all__:如果模块中导入了其他子模块(如import sub_module),__all__不会自动包含子模块,除非显式将子模块名加入__all__。
总结
__all__≠import *:前者是“模块的公开成员清单”(变量),后者是“批量导入语法”,前者专门约束后者的行为。__all__需手动定义:模块默认没有__all__,只有显式定义后才存在,用于精确控制import *的导入范围。- 无
__all__时的默认规则:import *导入所有“非单下划线开头”的成员,遵循 Python 内部成员的命名约定。
简单说:__all__ 是模块开发者给 import * 画的“红线”——告诉外部“批量导入时,只能拿这些成员”,是 Python 模块化设计中“控制接口暴露”的重要工具。

浙公网安备 33010602011771号