簡體   English   中英

如何在大型 python 項目中構建導入

[英]How to structure imports in a large python project

我已經閱讀了很多關於 Python 導入的“操作方法”文章(以及相關的 SO 問題),但是我正在努力弄清楚在大型 Python 項目中管理導入的“最佳實踐”是什么。 例如,假設我有一個如下所示的項目結構(這過於簡單化了):

test/                     
    packA/                 
        subA/             
            __init__.py
            sa1.py
            sa2.py
        __init__.py
        a1.py
        a2.py
    packB/                 
        b1.py
        b2.py
    main.py

並在packA/subA/sa1.py里面說我想從packB/b1.py導入代碼。 更一般地說,我希望能夠在項目內的包/子包之間自由導入。

根據我目前的理解,go 有四種方法可以做到這一點:

選項1

將我的項目根目錄永久添加到 PYTHONPATH 並在項目中的任何地方使用絕對導入。 所以在 packA/subA/sa1.py 我會有

from packB import b1

隨着項目樹變大,這可能會有點混亂,例如

from packB.subC.subD.subE import f1

選項 2

與上面相同,但我沒有修改 PYTHONPATH 以包含項目根目錄,而是堅持只從項目根目錄執行 python (這樣根目錄始終是工作目錄)。

選項 3

使用相對導入

from...packB import b1

我不喜歡這個,因為它不容易閱讀,而且我讀過的所有地方通常都說相對導入是一個壞主意。

選項 4

使用 setuptools/setup.py 腳本並使用 pip 安裝我的包,這樣我就可以在任何地方導入。

這似乎有點矯枉過正,因為所有代碼都已經在項目文件夾中(並且每次 package 更改時都必須重新安裝)並且還可能導致依賴項/版本管理令人頭疼。


所以我的問題是,以上哪一項(如果有的話)被認為是最佳實踐? 我目前在 1 和 2 之間猶豫不決,但很高興聽到更優雅/Pythonic 的方法。

注意:我使用的是 Python 3.6

重新設計

您可以做的第一件事是重新設計您的 package。 說真的,直接來自pep20 python zen

平面優於嵌套。

因此,您應該嘗試減少 package 中嵌套文件夾的數量。 例如from mypackage.module1.module2.module3 import foo不應該存在。 唯一一次您會看到模塊嵌套在非常大且成熟的軟件包中,例如djangotensorfow 即使這樣,您也會注意到它們的 api 仍然非常短(即from django.test import TestCase ),即使它們的內部模塊很復雜且嵌套。 通常,長且嵌套的導入是 Python 中 package 設計不良的信號。

另外,如果 package A 和 package B 相互依賴(co-dependent),那么它們真的應該在同一個 package 下,你需要重新考慮你的設計。


我的意見

我總是喜歡遵循flaskkeras庫中的標准。 特別是keras API 對我來說一直很直觀。 我經常 go 到那個 repo 來激發我自己的編碼實踐。 就個人而言,我嘗試盡可能使用相對導入,因為我構建的大多數東西都很小(沒有嵌套,或者一層嵌套)。 但是我知道許多較大的項目選擇使用絕對導入,因為它們有更多的嵌套層。

我從“keras”庫中采用的一件事是進口的特異性和可用性之間的平衡。 要導入Conv2D層,它並不像以下那樣通用:

from keras import Conv2D

但它也不是那么具體:

from keras.layers.convolational import Conv2D

中間有一個很好的:

from keras.layers import Conv2D

但是,如果我們仔細查看keras ,您會注意到Conv2D class 仍然包含在其自己的文件convolutional.py中。 他們可以通過在 layers 模塊的__init__.py中添加以下行來降低導入的特異性:

from .convolutional import Conv2D

這允許您保留用於開發的包/模塊結構,但保持客戶端 api 簡單直觀。


使用 Pip

絕對不要go 用於選項 1。 pip 包的目的是您不需要向PYTHONPATH添加隨機路徑。 這不是可擴展的,這意味着代碼不能在其他機器上運行,也不能作為獨立的 package 而不編輯PYTHONPATH 最好在每個 package 中都有一個setup.py並通過pip安裝東西。

一直不得不pip uninstall. pip install. 每次您對 package 進行更改時,這就是pip具有-e標志的原因:

pip install -e .

-e標志是可編輯的安裝,它會安裝 package,這樣您對代碼所做的任何更改都會立即生效,因此您不必在更改后繼續卸載和重新安裝pip

正如我在這里的回答,如果你想構建嵌套文件夾,你可以在每個 python 文件中添加下面的簡單代碼來處理這個問題:

import os
import sys
if os.path.dirname(os.path.abspath(__file__)) not in sys.path:
    sys.path.append(os.path.dirname(os.path.abspath(__file__)))

如果有更好的解決方案,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM