简体   繁体   English

导入第三方 Python 项目而不将其添加到 sys.path

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

I am trying to import a third party python 'project' in my own code.我正在尝试在我自己的代码中导入第三方 python '项目'。 I am not referring it as a package because it seems to be prepared for running on its own but not for others to import it and run it somewhere else.我没有将它称为 package,因为它似乎已准备好自行运行,而不是其他人将其导入并在其他地方运行。 For example, that third party project may look like this:例如,该第三方项目可能如下所示:

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

and the dependency of files/functions goes like:文件/函数的依赖关系如下:

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

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

such that这样

  1. running main.py requires the function xxx from lib/functions.py , and运行main.py需要来自lib/functions.py的 function xxx ,并且
  2. running the function xxx in lib/functions.py requires the function yyy in utils.tools.py .lib/functions.py中运行 function xxx需要 utils.tools.py 中的utils.tools.py yyy

If I run main.py at the top level of Project A, both lib and utils are visible at this level so main.py runs successfully.如果我在项目 A 的顶层运行main.py ,则libutils在此级别都是可见的,因此main.py可以成功运行。 Or, if I want to run the functions inside main.py somewhere else, I can add path_to_ProjectA to sys.path and everything runs well too.或者,如果我想在其他地方运行main.py中的函数,我可以将path_to_ProjectA添加到sys.path并且一切运行良好。

However, there are occasions in which I prefer not to add this project to sys.path .但是,在某些情况下,我不想将此项目添加到sys.path For example, I might want to use another project ProjectB which also has a utils submodule, or I already have a utils submodule in my own project.例如,我可能想使用另一个项目ProjectB ,它也有一个utils子模块,或者我自己的项目中已经有一个utils子模块。 In these cases, if I add both ProjectA and ProjectB to sys.path , then only one of utils submodules will get recognized (ie, can be imported).在这些情况下,如果我将ProjectAProjectB都添加到sys.path ,那么只有一个utils子模块将被识别(即可以导入)。

Therefore, I am wondering if there would be methods to make another's project available for importing.因此,我想知道是否有方法可以使另一个项目可用于导入。 What I can think of is to make the project a 'legit' package, eg, adding __init__.py at each level, changing the way to import packages/functions, etc. (Actually, I do not have much experience in doing this, and I do not have a clear idea about how too.) However, I do not believe this is always practical, especially when that project is sizeable and it may require fair understanding to the design of the project structure.我能想到的是让项目成为一个“合法”的package,例如,在每个级别添加__init__.py ,更改导入包/函数的方式等。(实际上,我没有太多这样做的经验,而且我也不清楚如何做。)但是,我不认为这总是可行的,尤其是当该项目规模很大并且可能需要对项目结构的设计有公平的理解时。

To summarize, my question is, what should I do so that I can import a third party python project outside that project without adding it to sys.path , even though that project is probably designed to be run only at its top directory level?总而言之,我的问题是,我应该怎么做才能在该项目之外导入第三方 python 项目而不将其添加到sys.path ,即使该项目可能设计为仅在其顶级目录级别运行?


Edit #1 (20220819)编辑 #1 (20220819)

Following @Lenntror 's comments, I am adding a minimal example here.在@Lenntror 的评论之后,我在这里添加了一个最小的示例。 The goal is to call ProjectA.lib.functions.xxx from the outside of ProjectA without adding ProjectA to sys.path .目标是从ProjectA ProjectA.lib.functions.xxxProjectA添加到sys.path

(a) Calling ProjectA.lib.functions.xxx inside ProjectA (a) 在ProjectA.lib.functions.xxx内部调用ProjectA

Structure of the third-party ProjectA :第三方ProjectA的结构:

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

Content of ProjectA/lib/functions.py : ProjectA/lib/functions.py的内容:

from utils.tools import yyy

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

Content of ProjectA/utils/tools.py : ProjectA/utils/tools.py的内容:

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

Content of ProjectA/main.py : ProjectA/main.py的内容:

from lib.functions import xxx

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

if __name__=='__main__' :
    main()

If I run python main.py under the directory ProjectA .如果我在ProjectA目录下运行python main.py It works:有用:

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

(b) Calling ProjectA.lib.functions.xxx outside ProjectA by adding ProjectA to sys.path (b) 通过将ProjectA添加到sys.path ,在ProjectA之外调用ProjectA.lib.functions.xxx

Let's say, I have another folder MyProject which is next to (and outside) ProjectA :假设,我有另一个文件夹MyProject ,它位于ProjectA旁边(和外部):

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

Content of MyProject/my_script.py : 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 also runs successfully:这也成功运行:

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

(c) Calling ProjectA.lib.functions.xxx by including ProjectA in a sub-directory/module (c) 通过在子目录/模块中包含ProjectA来调用ProjectA.lib.functions.xxx

Now, I have a script in another folder also outside of ProjectA .现在,我在ProjectA之外的另一个文件夹中有一个脚本。 This time, I include ProjectA inside this folder like this:这一次,我将ProjectA包含在这个文件夹中,如下所示:

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

Content of MyProject2/my_script.py : 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()

This gives an error:这给出了一个错误:

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'

So you could have the project file as this:所以你可以有这样的项目文件:

    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.py , ProjectA and ProjectB are sitting inside the same directory. your_project_file.pyProjectAProjectB位于同一目录中。

inside your_project_file.py you could use import statements like this:your_project_file.py中,您可以使用如下导入语句:

from ProjectA.lib.functions import xxx

But I think you figured this out already that this will cause issue from utils.tool .但我认为您已经意识到这将导致utils.tool问题。 What you need to do, is use relative path.您需要做的是使用相对路径。 Edit lib/functions.py file and place a dot in front of utils.tool which should become from.utils.tool import yyy编辑lib/functions.py文件并在utils.tool前面放置一个点,它应该变成from.utils.tool import yyy

Now it should resolve your problem and import in your_project_file.py should work fine.现在它应该可以解决您的问题,并且导入your_project_file.py应该可以正常工作。 If not, then you need to define __init__.py file for all folders.如果没有,那么您需要为所有文件夹定义__init__.py文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM