简体   繁体   English

如何从不同目录正确运行 python 项目

[英]How can I run properly python project from different directory

python project files hierarchy: python 项目文件层次结构:

parent/
    __init__.py
    one/
        __init__.py
        bar.py
    two/
       __init__.py
       foo.py

foo.py foo.py

from one import bar

I tried to run foo.py from terminal in other directory (eg users/user), I got the next error:我试图从其他目录(例如用户/用户)的终端运行 foo.py,我得到了下一个错误:

No module named one没有名为一个的模块

When I trying to run foo.py, I guess it is trying to import the files from the directory that the code had been executed from, I had tried lot of ways and I couldn't find solution, finally I found a solution, the problem with this solution is that the solution is not elegant and I hope there is an elegant and better solution.当我尝试运行 foo.py 时,我猜它正在尝试从执行代码的目录中导入文件,我尝试了很多方法,但我找不到解决方案,最后我找到了解决方案,这个解决方案的问题是这个解决方案并不优雅,我希望有一个优雅和更好的解决方案。

foo.py foo.py

from pathlib import Path
import sys

sys.path.append(str(Path(__file__).parent.parent))
sys.path.append("..")

from one import bar
  • This solution is not elegant because it preventing me to put all the imports in the start of the page.这个解决方案并不优雅,因为它阻止我将所有导入都放在页面的开头。

The fact that you have an __init.py__ in the parent directory suggests that parent is part of your package structure and that its parent directory, whatever that might be, should be in the PATH.您在parent目录中有一个__init.py__的事实表明, parent目录是您的 package 结构的一部分,并且它的父目录(无论可能是什么)都应该在 PATH 中。 Therefore your import should really be:因此,您的导入实际上应该是:

from parent.one import bar

It can be useful for an application directory structure to have a single root.应用程序目录结构具有单个根可能很有用。 Then the __init.py__ in that single root package can be used to load modules from subpackages, but this is certainly not a requirement.然后可以使用单根__init.py__中的 __init.py__ 从子包中加载模块,但这当然不是必需的。 If that was not your intention, then you should probably delete the __init__.py that is in parent as it is serving no purpose (and is confusing) and ensure that directory parent is in your PATH.如果这不是您的意图,那么您可能应该删除parent目录中的__init__.py ,因为它没有任何用途(并且令人困惑)并确保目录parent目录在您的 PATH 中。

HOWEVER : As long as the current directory you are in when you run your program is the parent directory of the root(s) of your package structure, Python should be able to find your packages with no special action on your part because the current directory is automatically added to the path.但是:只要您在运行程序时所在的当前目录是 package 结构的根目录的父目录,Python 应该能够找到您的包而无需您采取任何特殊措施,因为当前目录会自动添加到路径中。 If that is inconvenient, you can set environment variable PYTHONPATH .如果这不方便,您可以设置环境变量PYTHONPATH

So, determine whether you should be changing your import statement or not based on which directories are part of your package structure.因此,根据 package 结构的一部分来确定是否应该更改导入语句。 Then you should arrange for Python to find your packages either by setting the current directory, PYTHONPATH, or sys.path to the required directory -- but do this once.然后,您应该安排 Python 通过将当前目录、PYTHONPATH 或sys.path设置为所需目录来查找您的包——但只执行一次。 If you have to set sys.path , I would do this in your main program at startup before it needs to include anything:如果您必须设置sys.path ,我会在启动时在您的主程序中执行此操作,然后才需要包含任何内容:

If foo.py is your main program, then at the top of the program I would have:如果foo.py是您的主程序,那么在程序的顶部我将拥有:

if __name__ == '__main__':
    from pathlib import Path
    import sys

    # if your import statement is: from parent.one import bar, then:
    sys.path.insert(0, str(Path(__file__).parent.parent))
    """
    # if your import statement is: from one import bar, then:
    sys.path.insert(0, str(Path(__file__).parent))
    """

Why don't you let the parent act like a path provider to the child, by creating a path dictionary?为什么不通过创建路径字典让父级充当子级的路径提供者? like this way:像这样:

class parent:
...
    def createPathDict(self):
        self.path_dict = {}
        self.path_dict ['parent'] = self.parentPath
        self.path_dict ['one'] = os.path.join(self.parentPath, 'one')
        self.path_dict ['two'] = os.path.join(self.parentPath, 'two')
        # self.path_dict ['three'] = …
        # ...

From child 'two' you import the dictionary like this (I assume you use classes):从孩子'两个'你导入字典是这样的(我假设你使用类):

class foo:

    def __init__(self, parent):
          self.parent = parent

    def addPathsToPythDirs(self):
         sys.path.insert(1, self.parent.path_dict ['one'])  # better
         # sys.path.insert(0, self.parent.path_dict [key])  
...

In that way you could keep your imports in foo.py这样你就可以把你的导入保存在 foo.py

Why use sys.path.append(path) instead of sys.path.insert(1, path)? 为什么使用 sys.path.append(path) 而不是 sys.path.insert(1, path)?

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

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