你在Python中遇過循環(huán)導(dǎo)入嗎?嗯,這是一種非常常見的程式碼味道,表示設(shè)計或結(jié)構(gòu)有問題。
循環(huán)導(dǎo)入範(fàn)例
循環(huán)導(dǎo)入是如何發(fā)生的? 當(dāng)兩個或多個相互依賴的模組在完全初始化之前嘗試導(dǎo)入時,通常會發(fā)生此導(dǎo)入錯誤。
假設(shè)我們有兩個模組:module_1.py 和 module_2.py。
# module_1.py from module_2 import ModY class ModX: mody_obj = ModY()
# module_2.py from module_1 import ModX class ModY: modx_obj = ModX()
在上面的程式碼片段中,module_1和module_2都是相互依賴的。
module_1 中 mody_obj 的初始化依賴 module_2,module_2 中 modx_obj 的初始化依賴 module_1。
這就是我們所說的循環(huán)依賴。兩個模組在嘗試互相載入時都會陷入導(dǎo)入循環(huán)。
如果我們執(zhí)行 module_1.py,我們將得到以下回溯。
Traceback (most recent call last): File "module_1.py", line 1, in <module> from module_2 import ModY File "module_2.py", line 1, in <module> from module_1 import ModX File "module_1.py", line 1, in <module> from module_2 import ModY ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
這個錯誤說明了循環(huán)導(dǎo)入的情況。當(dāng)程式嘗試從 module_2 導(dǎo)入 ModY 時,當(dāng)時 module_2 尚未完全初始化(由於另一個導(dǎo)入語句嘗試從 module_1 導(dǎo)入 ModX)。
如何修正 Python 中的循環(huán)導(dǎo)入? 有多種方法可以消除 Python 中的循環(huán)導(dǎo)入。
修復(fù) Python 中的循環(huán)導(dǎo)入
將程式碼移至公用文件中
我們可以將程式碼移到一個公開檔案中以避免匯入錯誤,然後嘗試從該檔案匯入模組。
# main.py ----> common file class ModX: pass class ModY: pass
在上面的程式碼片段中,我們將類別 ModX 和 ModY 移到一個公用檔案 (main.py) 中。
# module_1.py from main import ModY class Mod_X: mody_obj = ModY()
# module_2.py from main import ModX class Mod_Y: modx_obj = ModX()
現(xiàn)在,module_1 和 module_2 從 main 導(dǎo)入類,修復(fù)了循環(huán)導(dǎo)入的情況。
這種方法有一個問題,有時程式碼庫太大,將程式碼移到另一個檔案中會存在風(fēng)險。
將導(dǎo)入移至模組末尾
我們可以將導(dǎo)入語句移到模組末尾。這將為導(dǎo)入另一個模組之前留出時間來完全初始化模組。
# module_1.py class ModX: pass from module_2 import ModY class Mod_X: mody_obj = ModY()
# module_2.py class ModY: pass from module_1 import ModX
在類別/函數(shù)範(fàn)圍內(nèi)導(dǎo)入模組
在類別或函數(shù)作用域內(nèi)導(dǎo)入模組可以避免循環(huán)導(dǎo)入。這允許僅在調(diào)用類別或函數(shù)時導(dǎo)入模組。當(dāng)我們想要最小化記憶體使用時,它是相關(guān)的。
# module_1.py class ModX: pass class Mod_X: from module_2 import ModY mody_obj = ModY()
# module_2.py class ModY: pass class Mod_Y: from module_1 import ModX modx_obj = ModX()
我們分別將 import 語句移至 module_1 和 module_2 中的類別 Mod_X 和 Mod_Y 範(fàn)圍內(nèi)。
如果我們執(zhí)行 module_1 或 module_2,我們不會收到循環(huán)導(dǎo)入錯誤。但是,這種方法使得類別只能在類別的範(fàn)圍內(nèi)訪問,因此我們無法全域利用導(dǎo)入。
使用模組名稱/別名
使用模組名稱或僅像這樣的別名可以解決問題。這允許兩個模組透過將循環(huán)依賴推遲到運(yùn)行時來完全加載。
# module_1.py from module_2 import ModY class ModX: mody_obj = ModY()
# module_2.py from module_1 import ModX class ModY: modx_obj = ModX()
使用 importlib 庫
我們也可以使用 importlib 函式庫動態(tài)導(dǎo)入模組。
Traceback (most recent call last): File "module_1.py", line 1, in <module> from module_2 import ModY File "module_2.py", line 1, in <module> from module_1 import ModX File "module_1.py", line 1, in <module> from module_2 import ModY ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
# main.py ----> common file class ModX: pass class ModY: pass
Python 套件中的循環(huán)導(dǎo)入
通常,循環(huán)導(dǎo)入 來自同一包內(nèi)的模組。在複雜的專案中,目錄結(jié)構(gòu)也很複雜,包內(nèi)包。
這些套件和子包包含 __init__.py 文件,以提供更輕鬆的模組存取。這就是有時無意中在模組之間產(chǎn)生循環(huán)依賴的地方。
我們有以下目錄結(jié)構(gòu)。
# module_1.py from main import ModY class Mod_X: mody_obj = ModY()
我們有一個 mainpkg 套件和一個 main.py 檔案。我們在 mainpkg 中有兩個子包 modpkg_x 和 modpkg_y。
這是 modpkg_x 和 modpkg_y 中每個 Python 檔的樣子。
mainpkg/modpkg_x/__init__.py
# module_2.py from main import ModX class Mod_Y: modx_obj = ModX()
此檔案從 module_1 和 module_1_1 匯入兩個類別(ModX 和 ModA)。
mainpkg/modpkg_x/module_1.py
# module_1.py class ModX: pass from module_2 import ModY class Mod_X: mody_obj = ModY()
module_1 從 module_2 匯入 ModY 類別。
mainpkg/modpkg_x/module_1_1.py
# module_2.py class ModY: pass from module_1 import ModX
module_1_1 沒有導(dǎo)入任何內(nèi)容。它不依賴任何模組。
mainpkg/modpkg_y/__init__.py
# module_1.py class ModX: pass class Mod_X: from module_2 import ModY mody_obj = ModY()
此檔案從 module_2 匯入 ModY 類別。
mainpkg/modpkg_y/module_2.py
# module_2.py class ModY: pass class Mod_Y: from module_1 import ModX modx_obj = ModX()
module_2 從 module_1_1 匯入 ModA 類別。
我們在 main.py 檔案中有以下程式碼。
root_dir/main.py
# module_1.py import module_2 as m2 class ModX: def __init__(self): self.mody_obj = m2.ModY()
主檔案從 module_2 匯入 ModY 類別。該檔案依賴 module_2。
如果我們在這裡視覺化導(dǎo)入週期,它看起來像下面忽略 modpkg_x 和 modpkg_y 中的 __init__.py 檔案。
我們可以看到主檔案依賴module_2,module_1也依賴module_2,module_2又依賴module_1_1。沒有導(dǎo)入週期。
但是你知道,模組依賴它們的 __init__.py 文件,因此 __init__.py 文件首先初始化,然後重新導(dǎo)入模組。
這就是現(xiàn)在的導(dǎo)入週期。
這使得 module_1_1 依賴 module_1,這是一個假依賴項。
如果是這種情況,清空子套件 __init__.py 檔案並使用單獨(dú)的 __init__.py 檔案可以幫助在套件層級集中匯入。
# module_1.py from module_2 import ModY class ModX: mody_obj = ModY()
在此結(jié)構(gòu)中,我們在 mainpkg 中加入了另一個子套件 subpkg。
mainpkg/subpkg/__init__.py
# module_2.py from module_1 import ModX class ModY: modx_obj = ModX()
這將允許內(nèi)部模組從單一來源導(dǎo)入,從而減少交叉導(dǎo)入的需要。
現(xiàn)在我們可以更新 main.py 檔案中的導(dǎo)入語句。
root_dir/main.py
Traceback (most recent call last): File "module_1.py", line 1, in <module> from module_2 import ModY File "module_2.py", line 1, in <module> from module_1 import ModX File "module_1.py", line 1, in <module> from module_2 import ModY ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
這解決了同一包內(nèi)模組之間的循環(huán)相依性問題。
結(jié)論
Python 中的循環(huán)依賴或?qū)胧且环N程式碼異味,這表明需要對程式碼進(jìn)行認(rèn)真的重構(gòu)和重構(gòu)。
您可以嘗試上述任何一種方法來避免 Python 中的循環(huán)依賴。
? 如果您喜歡這篇文章,您可能也會感興趣
?Flask 中的範(fàn)本繼承範(fàn)例。
?exec() 和 eval() 之間的差異並舉例。
?了解Python中g(shù)lobal關(guān)鍵字的使用。
?Python 類型提示:函數(shù)、傳回值、變數(shù)。
?為什麼在函數(shù)定義中使用斜線和星號。
?學(xué)習(xí)率如何影響 ML 與 DL 模型?
現(xiàn)在就這些。
繼續(xù)編碼??。
以上是在 Python 中修復(fù)循環(huán)導(dǎo)入的不同方法的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

處理API認(rèn)證的關(guān)鍵在於理解並正確使用認(rèn)證方式。 1.APIKey是最簡單的認(rèn)證方式,通常放在請求頭或URL參數(shù)中;2.BasicAuth使用用戶名和密碼進(jìn)行Base64編碼傳輸,適合內(nèi)部系統(tǒng);3.OAuth2需先通過client_id和client_secret獲取Token,再在請求頭中帶上BearerToken;4.為應(yīng)對Token過期,可封裝Token管理類自動刷新Token;總之,根據(jù)文檔選擇合適方式,並安全存儲密鑰信息是關(guān)鍵。

在Python中同時遍歷兩個列表的常用方法是使用zip()函數(shù),它會按順序配對多個列表並以最短為準(zhǔn);若列表長度不一致,可使用itertools.zip_longest()以最長為準(zhǔn)並填充缺失值;結(jié)合enumerate()可同時獲取索引。 1.zip()簡潔實(shí)用,適合成對數(shù)據(jù)迭代;2.zip_longest()處理不一致長度時可填充默認(rèn)值;3.enumerate(zip())可在遍歷時獲取索引,滿足多種複雜場景需求。

Inpython,IteratorSareObjectSthallowloopingThroughCollectionsByImplementing_iter __()和__next __()。 1)iteratorsWiaTheIteratorProtocol,使用__ITER __()toreTurnterateratoratoranteratoratoranteratoratorAnterAnteratoratorant antheittheext__()

要使用Python創(chuàng)建現(xiàn)代高效的API,推薦使用FastAPI;其基於標(biāo)準(zhǔn)Python類型提示,可自動生成文檔,性能優(yōu)越。安裝FastAPI和ASGI服務(wù)器uvicorn後,即可編寫接口代碼。通過定義路由、編寫處理函數(shù)並返回數(shù)據(jù),可以快速構(gòu)建API。 FastAPI支持多種HTTP方法,並提供自動生成的SwaggerUI和ReDoc文檔系統(tǒng)。 URL參數(shù)可通過路徑定義捕獲,查詢參數(shù)則通過函數(shù)參數(shù)設(shè)置默認(rèn)值實(shí)現(xiàn)。合理使用Pydantic模型有助於提升開發(fā)效率和準(zhǔn)確性。

要測試API需使用Python的Requests庫,步驟為安裝庫、發(fā)送請求、驗(yàn)證響應(yīng)、設(shè)置超時與重試。首先通過pipinstallrequests安裝庫;接著用requests.get()或requests.post()等方法發(fā)送GET或POST請求;然後檢查response.status_code和response.json()確保返回結(jié)果符合預(yù)期;最後可添加timeout參數(shù)設(shè)置超時時間,並結(jié)合retrying庫實(shí)現(xiàn)自動重試以增強(qiáng)穩(wěn)定性。

在Python中,函數(shù)內(nèi)部定義的變量是局部變量,僅在函數(shù)內(nèi)有效;外部定義的是全局變量,可在任何地方讀取。 1.局部變量隨函數(shù)執(zhí)行結(jié)束被銷毀;2.函數(shù)可訪問全局變量但不能直接修改,需用global關(guān)鍵字;3.嵌套函數(shù)中若要修改外層函數(shù)變量,需使用nonlocal關(guān)鍵字;4.同名變量在不同作用域互不影響;5.修改全局變量時必須聲明global,否則會引發(fā)UnboundLocalError錯誤。理解這些規(guī)則有助於避免bug並寫出更可靠的函數(shù)。

是的,你可以使用Python和Pandas解析HTML表格。首先,使用pandas.read_html()函數(shù)提取表格,該函數(shù)可將網(wǎng)頁或字符串中的HTML元素解析為DataFrame列表;接著,若表格無明確列標(biāo)題,可通過指定header參數(shù)或手動設(shè)置.columns屬性修復(fù);對於復(fù)雜頁面,可結(jié)合requests庫獲取HTML內(nèi)容或使用BeautifulSoup定位特定表格;注意JavaScript渲染、編碼問題及多表識別等常見陷阱。

在Python中訪問嵌套JSON對象的方法是先明確結(jié)構(gòu),再逐層索引。首先確認(rèn)JSON的層級關(guān)係,例如字典嵌套字典或列表;接著使用字典鍵和列表索引逐層訪問,如data"details"["zip"]獲取zip編碼,data"details"[0]獲取第一個愛好;為避免KeyError和IndexError,可用.get()方法設(shè)置默認(rèn)值,或封裝函數(shù)safe_get實(shí)現(xiàn)安全訪問;對於復(fù)雜結(jié)構(gòu),可遞歸查找或使用第三方庫如jmespath處理。
