Python中的__all__:模块公开API设计的关键工具

在Python项目中,我们经常会看到类似这样的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
__all__ = [
    "Field",
    "FormRequest",
    "Item",
    "Request",
    "Selector",
    "Spider",
    "__version__",
    "version_info",
]

很多初学者会疑惑:

  • __all__是做什么的?
  • 为什么需要它?
  • _xxx命名有什么区别?
  • 大型项目为什么经常使用?

本文将从基础语法到工程实践,深入理解 Python 的__all__

信息

上面所列代码来自scrapy

什么是__all__

__all__是Python模块中的一个特殊变量,用来定义:当使用from xxx import *时,哪些成员会被导入。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
__all__ = ["add", "VERSION"]

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b


VERSION = "1.0.0"
_debug = True

其他地方:

1
2
3
4
5
6
from math_utils import *

print(add(5, 3)) # 可以
print(subtract(5, 3)) # 不存在
print(VERSION) # 可以
print(_debug) # 不存在

__all__明确告诉Python,这个模块对外公开的内容只有addVERSION

没有__all__会发生什么?

如果没有定义__all__

1
2
3
4
5
6
7
8
9
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b


VERSION = "1.0.0"
_debug = True

执行from math_utils import *。Python默认规则会导入所有不以下划线_开头的名字。因此addsubstractVERSION都会被导入,而_debug不会。所以很多Python项目会使用_name表示内部成员。

__all___xxx的区别

_xxx只是一个命名约定。表示这个东西是内部实现的,不建议外部使用

例如:

1
2
3
4
5
6
7
8
class Camera:
    def start(self):
        pass


class _CameraWorker:
    def run(self):
        pass

但是Python不禁止from camera import _CameraWorker依然可以。而__all__,是真正控制from camera import *导出的列表。

__all__可以暴露内部成员吗?

可以。例如:

1
2
3
4
5
__all__ = ["_calculate"]


def _calculate():
    return 100
1
2
3
from calculate import *

_calculate() #可以

__all__优先级高于_规则。

为什么大型项目需要__all__

小项目可能感觉不到价值。但在大型工程中,一个模块可能包含:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Camera:
    def start(self):
        pass


class _CameraWorker:
    def run(self):
        pass

class CameraFactory:
    def create_camera(self):
        pass

class CameraLogger:
    def log(self, message):
        pass

def _test_camera():
    pass

def _debug():
    pass

如果没有管理,用户不知道哪些是稳定API,哪些只是内部实现。例如:from camera import *可能导入几十个东西。这会导致命名污染、API不稳定、重构困难等问题。而使用:

1
__all__ = [ "Camera", "CameraFactory" ]

模块边界清晰。

在包中的作用

Python项目经常这样组织:

  • vision
    • __init__.py
    • camera.py
    • calibration.py
    • matcher.py
1
2
3
4
5
6
7
8
9
__all__ = [ "Camera" ]

class Camera:
    def start(self):
        pass

class CameraDebugTool:
    def debug(self):
        pass

然后:

1
2
3
4
from .camera import Camera
from .calibration import Calibration

__all__ = [ "Camera", "Calibration" ]

外部使用时:

1
from vision import Camera

而不用:

1
from vision.camera import Camera

这就是典型的Facade设计。

工程实践建议

__all__看似只是一个列表,但在大型项目中,它实际上承担的是:模块 API 设计、依赖隔离、架构演进的作用

以下是工程中使用__all__ 的核心原则:

  • 明确模块边界
  • 只暴露稳定 API
  • 隐藏内部实现
  • 减少模块耦合
  • 保护未来重构空间
  • 让包结构更加清晰
  • 把它当作 API 设计工具,而不是语法技巧

好的 Python 工程,不只是写功能,更重要的是设计清晰的模块出口。

总结

__all__的核心思想:

明确模块边界,控制公开接口。

它不是权限系统,也不是安全机制。它更像是一份模块API清单。在简单脚本中可以不用。在大型Python工程中,建议使用。合理设计__all__可以让代码:

  • 更容易维护
  • 更容易扩展
  • 更少依赖内部实现

推荐

Python Docs Modules

What does __all__ mean in Python?


相关内容

请作者喝杯咖啡!
AndyFree96 支付宝支付宝
AndyFree96 微信微信