簡體   English   中英

導入第三方 Python 項目而不將其添加到 sys.path

[英]Import a Third Party Python Project without Adding It to sys.path

我正在嘗試在我自己的代碼中導入第三方 python '項目'。 我沒有將它稱為 package,因為它似乎已准備好自行運行,而不是其他人將其導入並在其他地方運行。 例如,該第三方項目可能如下所示:

ProjectA/
|- utils/
  |- tools.py
|- lib/
  |- functions.py
|- main.py

文件/函數的依賴關系如下:

In main.py:
- from lib.functions import xxx

In lib/functions.py:
- from utils.tools import yyy

這樣

  1. 運行main.py需要來自lib/functions.py的 function xxx ,並且
  2. lib/functions.py中運行 function xxx需要 utils.tools.py 中的utils.tools.py yyy

如果我在項目 A 的頂層運行main.py ,則libutils在此級別都是可見的,因此main.py可以成功運行。 或者,如果我想在其他地方運行main.py中的函數,我可以將path_to_ProjectA添加到sys.path並且一切運行良好。

但是,在某些情況下,我不想將此項目添加到sys.path 例如,我可能想使用另一個項目ProjectB ,它也有一個utils子模塊,或者我自己的項目中已經有一個utils子模塊。 在這些情況下,如果我將ProjectAProjectB都添加到sys.path ,那么只有一個utils子模塊將被識別(即可以導入)。

因此,我想知道是否有方法可以使另一個項目可用於導入。 我能想到的是讓項目成為一個“合法”的package,例如,在每個級別添加__init__.py ,更改導入包/函數的方式等。(實際上,我沒有太多這樣做的經驗,而且我也不清楚如何做。)但是,我不認為這總是可行的,尤其是當該項目規模很大並且可能需要對項目結構的設計有公平的理解時。

總而言之,我的問題是,我應該怎么做才能在該項目之外導入第三方 python 項目而不將其添加到sys.path ,即使該項目可能設計為僅在其頂級目錄級別運行?


編輯 #1 (20220819)

在@Lenntror 的評論之后,我在這里添加了一個最小的示例。 目標是從ProjectA ProjectA.lib.functions.xxxProjectA添加到sys.path

(a) 在ProjectA.lib.functions.xxx內部調用ProjectA

第三方ProjectA的結構:

ProjectA/
|-- lib
|   |-- __init__.py # Empty
|   `-- functions.py
|-- utils
    |-- __init__.py # Empty
    `-- tools.py
`-- main.py

ProjectA/lib/functions.py的內容:

from utils.tools import yyy

def xxx() :
    print("This is xxx().")
    print("Now xxx() calls yyy().")
    yyy()

ProjectA/utils/tools.py的內容:

def yyy() :
    print("This is yyy().")

ProjectA/main.py的內容:

from lib.functions import xxx

def main() :
    print("This is main().")
    print("Now calling xxx().")
    xxx()

if __name__=='__main__' :
    main()

如果我在ProjectA目錄下運行python main.py 有用:

This is main().
Now calling xxx(). 
This is xxx().      
Now xxx() calls yyy().
This is yyy().

(b) 通過將ProjectA添加到sys.path ,在ProjectA之外調用ProjectA.lib.functions.xxx

假設,我有另一個文件夾MyProject ,它位於ProjectA旁邊(和外部):

./
|-- MyProject                                                               
|   `-- my_script.py    
|                                                    
`-- ProjectA
    |-- ...

MyProject/my_script.py的內容:

import sys
sys.path.append("../ProjectA")
from lib.functions import xxx

def main() :
    print("This is outside of ProjectA.")
    print("Now calling xxx().")
    xxx()

if __name__=='__main__' :
    main()

這也成功運行:

This is outside of ProjectA.
Now calling xxx().
This is xxx().
Now xxx() calls yyy().
This is yyy().         

(c) 通過在子目錄/模塊中包含ProjectA來調用ProjectA.lib.functions.xxx

現在,我在ProjectA之外的另一個文件夾中有一個腳本。 這一次,我將ProjectA包含在這個文件夾中,如下所示:

MyProject2/
|-- my_script.py
`-- thirdparty
    `-- ProjectA
        |-- ...

MyProject2/my_script.py的內容:

from thirdparty.ProjectA.lib.functions import xxx

def main() :
    print("This is outside of ProjectA.")
    print("Now calling xxx().")
    xxx()

if __name__=='__main__' :
    main()

這給出了一個錯誤:

Traceback (most recent call last):
  File "my_script.py", line 1, in <module>
    from thirdparty.ProjectA.lib.functions import xxx
  File "/workspace/MyProject2/thirdparty/ProjectA/lib/functions.py", line 1, in <module>
    from utils.tools import yyy
ModuleNotFoundError: No module named 'utils'

所以你可以有這樣的項目文件:

    ProjectA/
    |- utils/
      |- tools.py
    |- lib/
      |- functions.py
    |- main.py
    
    ProjectB/
    |- utils/
      |- tools.py
    |- lib/
      |- functions.py
    |- main.py

    your_project_file.py

your_project_file.pyProjectAProjectB位於同一目錄中。

your_project_file.py中,您可以使用如下導入語句:

from ProjectA.lib.functions import xxx

但我認為您已經意識到這將導致utils.tool問題。 您需要做的是使用相對路徑。 編輯lib/functions.py文件並在utils.tool前面放置一個點,它應該變成from.utils.tool import yyy

現在它應該可以解決您的問題,並且導入your_project_file.py應該可以正常工作。 如果沒有,那么您需要為所有文件夾定義__init__.py文件。

暫無
暫無

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

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