Python中__all__用法及常见误区详解

 更新时间:2025年12月29日 10:17:26   作者:MediaTea  
__all__属性是Python中用来控制模块导入行为的关键工具,它可以帮助你保持代码的整洁和封装性,防止意外地暴露内部实现细节,这篇文章主要介绍了Python中__all__用法及常见误区的相关资料,需要的朋友可以参考下

前言

在 Python 的模块与包体系中,__all__ 是一个看似简单却极具控制力的变量。它用于定义一个模块或包在使用 from xxx import * 时的公开接口(Public API),是实现封装、接口管理与工程化代码结构的关键工具。

Python 的导入机制向来强调“显式优于隐式”,而 __all__ 正体现了这一哲学:作者显式决定用户能看到什么、不能看到什么。

一、__all__ 的作用概述

在任何模块或者包的 __init__.py 中,只要定义了:

__all__ = ["name1", "name2", ...]

那么当用户执行:

from module import *

只有 __all__ 中列出的名称会被导入。

它本质上是一个导出白名单。

如果模块或包没有定义 __all__,那么:

from module import *

将导入所有不以下划线 _ 开头的名称。

示例:

# module.pyx = 1_y = 2def func(): pass

执行:

from module import *print(dir())

结果包含:

xfunc

而 _y 被视为“内部名称”,不会被导入。

这也是为什么企业级项目往往认为 from ... import * 不够安全:

没定义 __all__ 时,公开接口是隐式推断的,容易产生污染与冲突。

二、__all__ 的标准写法与行为

(1)基本示例

# mathutils.py__all__ = ["add", "mul"]
def add(a, b):    return a + b
def mul(a, b):    return a * b
def _secret():    return "hidden"

用户端:

from mathutils import *
print(add(1, 2))print(mul(2, 3))_secret()   # 报错:未导入

_secret 即使不以下划线开头,也不会被导入。

(2)在包的 __init__.py 中使用 __all__

位置结构:

mypkg/    __init__.py    a.py    b.py

__init__.py:

from .a import func_afrom .b import func_b
__all__ = ["func_a", "func_b"]

用户只需:

from mypkg import *

即可获得统一后的公共接口。

(3)在多级包中的控制

层级结构:

mypkg/    __init__.py    utils/        __init__.py        io.py

两层都可使用 __all__ 各自管理对上层的可见性,最终决定用户能访问什么。

三、__all__ 的设计动机

企业级项目通常强调 API 的稳定性与可控性,而 __all__ 能解决三个工程痛点。

(1)防止命名污染(避免 * 导入把内部逻辑暴露出去)

没有 __all__ 时,一个模块中新增任何“非下划线名称”,都会被自动公开,导致 API 不稳定。

(2)构建“面向用户的公共接口”

特别是在复杂包的 __init__.py 中,可以用 __all__ 构建统一接口层,让用户与内部结构解耦。

(3)稳固的封装机制

封装不仅是“不让别人看到”,更重要是“不让别人依赖内部结构”。

__all__ 让维护者可以明确声明 “这是对外 API,其余均为内部实现”。

四、常见使用模式

(1)显式导出函数与类

__all__ = ["A", "B", "utility"]
class A: ...class B: ...def utility(): ...

(2)阻止特定名称被导入

即使不以下划线开头,也可阻止导出:

def internal_logic():    ...
__all__ = ["api"]

(3)组合多个子模块的接口成为统一 API

# __init__.pyfrom .math import add, subfrom .string import format_name
__all__ = ["add", "sub", "format_name"]

这让包即使内部结构复杂,对外接口仍保持整洁一致。

(4)动态构建 __all__

有时模块想自动暴露所有非下划线名称,但仍显式控制:

__all__ = [name for name in globals() if not name.startswith("_")]

或按规则过滤:

__all__ = [name for name in globals() if callable(globals()[name])]

适用于自动化驱动的大型工具包。

五、常见误区澄清

误区 1:__all__ 会影响普通 import

例如:

import mathutilsmathutils.func()  # 无论 __all__ 是否包含 func,都可访问

说明:

__all__ 仅影响 from module import *,不影响普通 import。

误区 2:定义了 __all__ 下划线函数就一定隐藏

错。

__all__ = ["_internal"]

from module import * 仍会导入 _internal,因为作者将其显式加入。

误区 3:在包中使用 __all__ 会自动导入模块

不会。

# __init__.py__all__ = ["a", "b"]

不会自动导入子模块 a.py 或 b.py,需要你显式写:

from . import a, b

六、完整示例(构建可维护的公共接口)

目录:

mypkg/    __init__.py    add.py    multiply.py

add.py:

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

multiply.py:

def mul(a, b):    return a * b

__init__.py:

from .add import addfrom .multiply import mul
__all__ = ["add", "mul"]
print("mypkg loaded.")

用户端:

from mypkg import *
print(add(1, 2))print(mul(2, 5))

小结

__all__ 是 Python 模块化体系中极具工程价值的接口控制工具。它通过显式定义“允许被星号导入的名称”,使开发者能够严格管理对外 API,避免命名污染,并让大型包的结构清晰而稳定。它不影响普通导入,但能有效隔离内部实现,是构建高质量可维护库的重要机制。

熟练使用 __all__,意味着你不仅理解模块的组织方式,更真正理解了 Python 的“接口哲学”——清晰、显式、可控。

到此这篇关于Python中__all__用法及常见误区的文章就介绍到这了,更多相关Python __all__用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • conda将python低版本环境升级到高版本的完整步骤

    conda将python低版本环境升级到高版本的完整步骤

    这篇文章主要给大家介绍了关于conda将python低版本环境升级到高版本的完整步骤,包括激活环境、升级Python版本、验证升级、处理依赖问题和测试环境等步骤,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-04-04
  • 为什么是 Python -m

    为什么是 Python -m

    这篇文章给大家介绍了Python -m的含义及python -m 和 python 的区别解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-06-06
  • 解决import tensorflow as tf 出错的原因

    解决import tensorflow as tf 出错的原因

    这篇文章主要介绍了解决import tensorflow as tf 出错的原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Django项目连接MongoDB的三种方法

    Django项目连接MongoDB的三种方法

    本文主要介绍了Django项目连接MongoDB的三种方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • 解决Python3.7.0 SSL低版本导致Pip无法使用问题

    解决Python3.7.0 SSL低版本导致Pip无法使用问题

    这篇文章主要介绍了解决Python3.7.0 SSL低版本导致Pip无法使用问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • 解决Keras的自定义lambda层去reshape张量时model保存出错问题

    解决Keras的自定义lambda层去reshape张量时model保存出错问题

    这篇文章主要介绍了解决Keras的自定义lambda层去reshape张量时model保存出错问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • 使用python进行广告点击率的预测的实现

    使用python进行广告点击率的预测的实现

    这篇文章主要介绍了使用python进行广告点击率的预测的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • python 获取页面表格数据存放到csv中的方法

    python 获取页面表格数据存放到csv中的方法

    今天小编就为大家分享一篇python 获取页面表格数据存放到csv中的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • Python用20行代码实现完整邮件功能

    Python用20行代码实现完整邮件功能

    这篇文章主要介绍了如何使用Python实现完整邮件功能的相关资料,需要的朋友可以参考下面文章内容,希望能帮助到您
    2021-09-09
  • pytorch 预训练层的使用方法

    pytorch 预训练层的使用方法

    今天小编就为大家分享一篇pytorch 预训练层的使用方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08

最新评论