Python中__all__用法及常見(jiàn)誤區(qū)詳解
前言
在 Python 的模塊與包體系中,__all__ 是一個(gè)看似簡(jiǎn)單卻極具控制力的變量。它用于定義一個(gè)模塊或包在使用 from xxx import * 時(shí)的公開(kāi)接口(Public API),是實(shí)現(xiàn)封裝、接口管理與工程化代碼結(jié)構(gòu)的關(guān)鍵工具。
Python 的導(dǎo)入機(jī)制向來(lái)強(qiáng)調(diào)“顯式優(yōu)于隱式”,而 __all__ 正體現(xiàn)了這一哲學(xué):作者顯式?jīng)Q定用戶能看到什么、不能看到什么。
一、__all__ 的作用概述
在任何模塊或者包的 __init__.py 中,只要定義了:
__all__ = ["name1", "name2", ...]
那么當(dāng)用戶執(zhí)行:
from module import *
只有 __all__ 中列出的名稱會(huì)被導(dǎo)入。
它本質(zhì)上是一個(gè)導(dǎo)出白名單。
如果模塊或包沒(méi)有定義 __all__,那么:
from module import *
將導(dǎo)入所有不以下劃線 _ 開(kāi)頭的名稱。
示例:
# module.pyx = 1_y = 2def func(): pass
執(zhí)行:
from module import *print(dir())
結(jié)果包含:
xfunc
而 _y 被視為“內(nèi)部名稱”,不會(huì)被導(dǎo)入。
這也是為什么企業(yè)級(jí)項(xiàng)目往往認(rèn)為 from ... import * 不夠安全:
沒(méi)定義 __all__ 時(shí),公開(kāi)接口是隱式推斷的,容易產(chǎn)生污染與沖突。
二、__all__ 的標(biāo)準(zhǔn)寫(xiě)法與行為
(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() # 報(bào)錯(cuò):未導(dǎo)入
_secret 即使不以下劃線開(kāi)頭,也不會(huì)被導(dǎo)入。
(2)在包的 __init__.py 中使用 __all__
位置結(jié)構(gòu):
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 *
即可獲得統(tǒng)一后的公共接口。
(3)在多級(jí)包中的控制
層級(jí)結(jié)構(gòu):
mypkg/ __init__.py utils/ __init__.py io.py
兩層都可使用 __all__ 各自管理對(duì)上層的可見(jiàn)性,最終決定用戶能訪問(wèn)什么。
三、__all__ 的設(shè)計(jì)動(dòng)機(jī)
企業(yè)級(jí)項(xiàng)目通常強(qiáng)調(diào) API 的穩(wěn)定性與可控性,而 __all__ 能解決三個(gè)工程痛點(diǎn)。
(1)防止命名污染(避免 * 導(dǎo)入把內(nèi)部邏輯暴露出去)
沒(méi)有 __all__ 時(shí),一個(gè)模塊中新增任何“非下劃線名稱”,都會(huì)被自動(dòng)公開(kāi),導(dǎo)致 API 不穩(wěn)定。
(2)構(gòu)建“面向用戶的公共接口”
特別是在復(fù)雜包的 __init__.py 中,可以用 __all__ 構(gòu)建統(tǒng)一接口層,讓用戶與內(nèi)部結(jié)構(gòu)解耦。
(3)穩(wěn)固的封裝機(jī)制
封裝不僅是“不讓別人看到”,更重要是“不讓別人依賴內(nèi)部結(jié)構(gòu)”。
__all__ 讓維護(hù)者可以明確聲明 “這是對(duì)外 API,其余均為內(nèi)部實(shí)現(xiàn)”。
四、常見(jiàn)使用模式
(1)顯式導(dǎo)出函數(shù)與類
__all__ = ["A", "B", "utility"] class A: ...class B: ...def utility(): ...
(2)阻止特定名稱被導(dǎo)入
即使不以下劃線開(kāi)頭,也可阻止導(dǎo)出:
def internal_logic(): ... __all__ = ["api"]
(3)組合多個(gè)子模塊的接口成為統(tǒng)一 API
# __init__.pyfrom .math import add, subfrom .string import format_name __all__ = ["add", "sub", "format_name"]
這讓包即使內(nèi)部結(jié)構(gòu)復(fù)雜,對(duì)外接口仍保持整潔一致。
(4)動(dòng)態(tài)構(gòu)建 __all__
有時(shí)模塊想自動(dòng)暴露所有非下劃線名稱,但仍顯式控制:
__all__ = [name for name in globals() if not name.startswith("_")]或按規(guī)則過(guò)濾:
__all__ = [name for name in globals() if callable(globals()[name])]
適用于自動(dòng)化驅(qū)動(dòng)的大型工具包。
五、常見(jiàn)誤區(qū)澄清
誤區(qū) 1:__all__ 會(huì)影響普通 import
例如:
import mathutilsmathutils.func() # 無(wú)論 __all__ 是否包含 func,都可訪問(wèn)
說(shuō)明:
__all__ 僅影響 from module import *,不影響普通 import。
誤區(qū) 2:定義了 __all__ 下劃線函數(shù)就一定隱藏
錯(cuò)。
__all__ = ["_internal"]
from module import * 仍會(huì)導(dǎo)入 _internal,因?yàn)樽髡邔⑵滹@式加入。
誤區(qū) 3:在包中使用 __all__ 會(huì)自動(dòng)導(dǎo)入模塊
不會(huì)。
# __init__.py__all__ = ["a", "b"]
不會(huì)自動(dòng)導(dǎo)入子模塊 a.py 或 b.py,需要你顯式寫(xiě):
from . import a, b
六、完整示例(構(gòu)建可維護(hù)的公共接口)
目錄:
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))
小結(jié)
__all__ 是 Python 模塊化體系中極具工程價(jià)值的接口控制工具。它通過(guò)顯式定義“允許被星號(hào)導(dǎo)入的名稱”,使開(kāi)發(fā)者能夠嚴(yán)格管理對(duì)外 API,避免命名污染,并讓大型包的結(jié)構(gòu)清晰而穩(wěn)定。它不影響普通導(dǎo)入,但能有效隔離內(nèi)部實(shí)現(xiàn),是構(gòu)建高質(zhì)量可維護(hù)庫(kù)的重要機(jī)制。
熟練使用 __all__,意味著你不僅理解模塊的組織方式,更真正理解了 Python 的“接口哲學(xué)”——清晰、顯式、可控。
到此這篇關(guān)于Python中__all__用法及常見(jiàn)誤區(qū)的文章就介紹到這了,更多相關(guān)Python __all__用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
將自己的數(shù)據(jù)集制作成TFRecord格式教程
今天小編就為大家分享一篇將自己的數(shù)據(jù)集制作成TFRecord格式教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02
學(xué)會(huì)使用Python?Configparser處理ini文件模塊
這篇文章主要為大家介紹了使用Python?Configparser處理ini文件模塊的學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
python matplotlib繪圖,修改坐標(biāo)軸刻度為文字的實(shí)例
今天小編就為大家分享一篇python matplotlib繪圖,修改坐標(biāo)軸刻度為文字的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05
一文掌握Python爬蟲(chóng)XPath語(yǔ)法
這篇文章主要介紹了一文掌握Python爬蟲(chóng)XPath語(yǔ)法,xpath是一門(mén)在XML和HTML文檔中查找信息的語(yǔ)言,可用來(lái)在XML和HTML文檔中對(duì)元素和屬性進(jìn)行遍歷,XPath 通過(guò)使用路徑表達(dá)式來(lái)選取 XML 文檔中的節(jié)點(diǎn)或者節(jié)點(diǎn)集。下面會(huì)更學(xué)習(xí)的介紹,需要的朋友可以參考一下2021-11-11
Python?Flask?JinJa2?語(yǔ)法使用示例詳解
這篇文章主要為大家介紹了Python?Flask?JinJa2?語(yǔ)法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
使用python編寫(xiě)簡(jiǎn)單的小程序編譯成exe跑在win10上
這篇文章主要介紹了使用python編寫(xiě)簡(jiǎn)單的小程序編譯成exe跑在win10上的相關(guān)資料,需要的朋友可以參考下2018-01-01
Python容器轉(zhuǎn)換與共有函數(shù)舉例詳解
Python容器是Python編程語(yǔ)言中非?;A(chǔ)且重要的概念,它們提供了數(shù)據(jù)的存儲(chǔ)和組織方式,下面這篇文章主要介紹了Python容器轉(zhuǎn)換與共有函數(shù)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-12-12
在Python的Flask框架中使用日期和時(shí)間的教程
這篇文章主要介紹了在Python的Flask框架中使用日期和時(shí)間的教程,包括對(duì)各個(gè)時(shí)區(qū)之間轉(zhuǎn)換的一些處理,需要的朋友可以參考下2015-04-04
Python中利用函數(shù)裝飾器實(shí)現(xiàn)備忘功能
這篇文章主要介紹了Python中利用函數(shù)裝飾器實(shí)現(xiàn)備忘功能,同時(shí)還降到了利用裝飾器來(lái)檢查函數(shù)的遞歸、確保參數(shù)傳遞的正確,需要的朋友可以參考下2015-03-03

