一、什么是 __all__?
__all__ 是 Python 模块中的一个特殊变量,用于定义当使用 from module import * 语句时,哪些名称会被导入。它是一个字符串列表,包含了模块中允许被公开访问的属性名。
二、__all__ 的基本用法
1. 定义模块的公开接口
# mymodule.py"""示例模块,演示 __all__ 的用法"""# 定义公开接口__all__ = ['public_function', 'PublicClass', 'public_variable']# 公开函数def public_function(): """这个函数会被导入""" return "Public function"# 公开类class PublicClass: """这个类会被导入""" pass# 公开变量public_variable = "Public variable"# 私有函数(以下划线开头)def _private_function(): """这个函数不会被导入""" return "Private function"# 私有变量_private_variable = "Private variable"# 未在 __all__ 中列出的函数def hidden_function(): """这个函数虽然不以_开头,但不在__all__中,也不会被导入""" return "Hidden function"# 未在 __all__ 中列出的变量hidden_variable = "Hidden variable"
2. 使用 from module import *
# test.py - 测试导入from mymodule import *# 这些可以正常使用print(public_function()) # 输出: Public functionobj = PublicClass() # 正常print(public_variable) # 输出: Public variable# 这些会引发 NameError# print(_private_function()) # 错误!未导入# print(_private_variable) # 错误!未导入# print(hidden_function()) # 错误!未导入# print(hidden_variable) # 错误!未导入
三、__all__ 的高级用法
1. 在包(Package)中使用 __all__
# mypackage/__init__.py"""包的初始化文件,定义包的公开接口"""# 定义包级别的 __all____all__ = ['module1', 'module2', 'utils']# 导入子模块from . import module1from . import module2from . import utils# 也可以导入具体的函数/类from .module1 import function_a, function_bfrom .module2 import ClassC, ClassD# 添加到 __all__ 中__all__.extend(['function_a', 'function_b', 'ClassC', 'ClassD'])
2. 动态构建 __all__
# dynamic_all.py"""动态构建 __all__ 列表"""import sysimport inspect# 获取模块中所有公开的函数和类def _get_public_names(): """动态获取公开名称""" public_names = [] for name, obj in inspect.getmembers(sys.modules[__name__]): # 不是私有名称(不以_开头) if not name.startswith('_'): # 是函数或类 if inspect.isfunction(obj) or inspect.isclass(obj): public_names.append(name) return public_names# 函数1def add(a, b): return a + b# 函数2def subtract(a, b): return a - b# 函数3def multiply(a, b): return a * b# 私有函数def _internal_helper(): pass# 类class Calculator: pass# 动态设置 __all____all__ = _get_public_names()# 测试if __name__ == "__main__": print(f"__all__ = {__all__}") # 输出: __all__ = ['add', 'subtract', 'multiply', 'Calculator']
3. 控制子模块的导出
# shapes/__init__.py"""图形包,控制导出哪些形状类"""# 只导出特定的类__all__ = ['Circle', 'Rectangle', 'Triangle']# 导入实现from .circle import Circlefrom .rectangle import Rectanglefrom .triangle import Trianglefrom .polygon import Polygon # Polygon 不会被导出# shapes/circle.pyclass Circle: def __init__(self, radius): self.radius = radius def area(self): return 3.14159 * self.radius ** 2# shapes/rectangle.pyclass Rectangle: def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height# shapes/triangle.pyclass Triangle: def __init__(self, base, height): self.base = base self.height = height def area(self): return 0.5 * self.base * self.height# shapes/polygon.pyclass Polygon: def __init__(self, sides): self.sides = sides # 这个类不会被导出# 使用包from shapes import *# 这些可以导入circle = Circle(5)rectangle = Rectangle(4, 6)triangle = Triangle(3, 4)# 这个会出错# polygon = Polygon(5) # NameError: name 'Polygon' is not defined
四、__all__ 的最佳实践
1. 明确文档化 API
# database/__init__.py"""数据库模块公开 API:- connect(): 建立数据库连接- execute(): 执行SQL语句- query(): 查询数据- DatabaseError: 数据库错误异常- Connection: 数据库连接类"""__all__ = [ 'connect', 'execute', 'query', 'DatabaseError', 'Connection']# 实现from .connection import connect, Connectionfrom .operations import execute, queryfrom .exceptions import DatabaseError# 内部模块不导出from .pool import _connection_poolfrom .cache import _query_cache
2. 版本兼容性
# compat/__init__.py"""兼容性模块,根据 Python 版本导出不同的 API"""import sysif sys.version_info >= (3, 8): # Python 3.8+ 的新功能 from .new_features import async_function, new_class __all__ = ['async_function', 'new_class']else: # 旧版本兼容实现 from .legacy import legacy_function, legacy_class __all__ = ['legacy_function', 'legacy_class']
3. 自动发现模块
# plugins/__init__.py"""插件系统,自动发现并导出所有插件"""import pkgutilimport inspect# 动态构建 __all____all__ = []# 自动发现当前包下的所有模块for loader, module_name, is_pkg in pkgutil.iter_modules(__path__): # 导入模块 module = __import__(f"{__name__}.{module_name}", fromlist=[module_name]) # 查找模块中的公开类(继承自 Plugin 基类) for name, obj in inspect.getmembers(module): if (inspect.isclass(obj) and hasattr(obj, '__bases__') and name not in __all__): # 添加到 __all__ __all__.append(name) # 导入到当前命名空间 globals()[name] = obj# plugins/base.pyclass Plugin: """插件基类""" pass# plugins/plugin_a.pyfrom .base import Pluginclass PluginA(Plugin): def execute(self): return "Plugin A"# plugins/plugin_b.py from .base import Pluginclass PluginB(Plugin): def execute(self): return "Plugin B"# 使用插件from plugins import *# 自动导入所有插件类plugin_a = PluginA()plugin_b = PluginB()print(plugin_a.execute()) # Plugin Aprint(plugin_b.execute()) # Plugin B
五、注意事项和常见陷阱
1. __all__ 不影响普通导入
# mymodule.py__all__ = ['public_func']def public_func(): return "Public"def private_func(): return "Private"# 测试from mymodule import private_func # 仍然可以导入!print(private_func()) # 正常工作# __all__ 只影响 from module import *
2. 子模块不会被自动导入
# mypackage/__init__.py__all__ = ['submodule'] # 只是声明,不会自动导入# 需要手动导入from . import submodule# 或者直接导入到命名空间from .submodule import function_a__all__.append('function_a')
3. 使用 __all__ 前要先定义
# 错误示例__all__ = ['func1', 'func2'] # 此时 func1, func2 还未定义def func1(): passdef func2(): pass# 正确示例def func1(): passdef func2(): pass__all__ = ['func1', 'func2'] # 在定义之后
4. 导入 __all__ 中的名称
# module.py__all__ = ['a', 'b']a = 1b = 2c = 3# 使用from module import * # 只导入 a, b# 但也可以直接导入 cfrom module import c # 仍然可以print(c) # 3
六、总结
__all__ 要点表格
| |
|---|
| 作用 | 定义 from module import * 时的导入列表 |
| 类型 | |
| 位置 | |
| 默认值 | |
| 影响范围 | 仅影响 from module import * 语句 |
使用场景总结
最佳实践
# 推荐的模块结构"""模块文档字符串,说明模块功能"""# 1. 定义公开接口__all__ = [ 'PublicClass', 'public_function', 'public_variable', '_internal_constant' # 也可以导出内部常量(不推荐)]# 2. 导入依赖import sysimport osfrom typing import Optional# 3. 定义常量DEFAULT_TIMEOUT = 30# 4. 定义公开类class PublicClass: """公开类""" pass# 5. 定义公开函数def public_function(): """公开函数""" pass# 6. 定义公开变量public_variable = "public"# 7. 内部实现(以下划线开头)def _internal_helper(): """内部函数""" passclass _InternalClass: """内部类""" pass# 8. 模块测试代码if __name__ == "__main__": # 测试代码 pass
__all__ 是 Python 中控制模块公开接口的重要机制,合理使用可以:
明确模块的公开 API
防止意外导入内部实现
提高代码的可维护性
为代码使用者提供清晰的接口文档