将Python搜索路径扩展到其他来源


106

我刚刚加入了一个具有相当大的现有代码库的项目。我们用linux开发,不使用和IDE。我们通过命令行运行。我试图弄清楚如何在运行项目模块时让python搜索正确的路径。例如,当我运行类似的内容时:

python someprojectfile.py

我懂了

ImportError: no module named core.'somemodule'

我认为所有导入的内容都是这样,我认为这是路径问题。

TLDR:

如何~/codez/project/在导入语句期间让Python搜索* .py文件以及所有文件和文件夹。

Answers:


171

有几种方法可以做到这一点:

  • 将环境变量设置PYTHONPATH为用冒号分隔的目录列表,以搜索导入的模块。
  • 在您的程序中,用于sys.path.append('/path/to/search')添加您希望Python搜索导入的模块的目录名称。sys.path只是Python在每次被要求导入模块时搜索的目录列表,您可以根据需要进行更改(尽管我不建议删除任何标准目录!)。Python启动时,您放入环境变量中的所有目录PYTHONPATH都将插入sys.path其中。
  • 用于site.addsitedir向添加目录sys.path。此和纯附加的区别在于,当您使用时addsitedir,它还会.pth在该目录中查找文件,并使用它们sys.path根据文件的内容向其中添加其他目录。有关更多详细信息,请参见文档。

您要使用哪一种取决于您的情况。请记住,当您将项目分发给其他用户时,他们通常会以某种方式安装该项目,以便Python的导入程序会自动检测到Python代码文件(即,程序包通常安装在site-packages目录中),因此,如果您弄乱了sys.path代码,当该代码在另一台计算机上运行时,可能是不必要的,甚至可能产生不利影响。对于开发而言,我会大胆猜测设置PYTHONPATH通常是最好的选择。

但是,当您使用仅在自己的计算机上运行的内容时(或当您进行非标准设置时(例如有时在Web应用程序框架中)),执行诸如此类的操作并非完全不常见。

import sys
from os.path import dirname
sys.path.append(dirname(__file__))

因此,如果我想说15个子目录,我将不得不分别添加每个子目录?
themaestro 2010年

并可以举一个命令行参数示例来更改PYTHONPATH吗?
themaestro 2010年

3
要设置PYTHONPATH:在.bashrcshell使用的启动文件中(如果不是Bash),请写入export PYTHONPATH=$PYTHONPATH:$HOME/codez/project。但是,如果您有一堆子目录,我将制作一个.pth文件并使用site.addsitedir。您可以创建一个sitecustomize可以为您调用该函数的模块。尝试将其放在~/.local/lib/python2.6/sitecustomize.py(代替您的Python版本),以便希望它可以自动导入。
David Z

我将以下内容放在我的.bashrc文件中,但是对于那些导入我仍然没有运气。有任何想法吗?我该如何制作.pth文件?导出PYTHONPATH = $ PYTHONPATH:$ HOME / adaifotis / codez /导出PYTHONPATH = $ PYTHONPATH:$ HOME / adaifotis / codez / project导出PYTHONPATH = $ PYTHONPATH:$ HOME / adaifotis / codez / project / core导出PYTHONPATH = $ PYTHONPATH:$ HOME / adaifotis / codez / project / proxies export PYTHONPATH = $ PYTHONPATH:$ HOME / adaifotis / codez / project / conf
themaestro 2010年

尝试打开一个终端并运行echo $PYTHONPATH。如果正确设置了环境变量,则应该看到用冒号分隔的目录列表。有关.pth文件的信息,请参见site我在答案中链接到的模块的文档。它告诉您内容应该是什么以及如何使用它们。
David Z 2010年

13

您还应该在这里阅读有关python软件包的信息:http : //docs.python.org/tutorial/modules.html

从您的示例中,我想您确实在拥有一个软件包~/codez/project__init__.pypython目录中的文件将目录映射到名称空间。如果所有子目录都有一个__init__.py文件,则只需将基本目录添加到中PYTHONPATH。例如:

PYTHONPATH = $ PYTHONPATH:$ HOME / adaifotis / project

正如David解释的那样,除了测试您的PYTHONPATH环境变量外,您还可以像这样在python中对其进行测试:

$ python
>>> import project                      # should work if PYTHONPATH set
>>> import sys
>>> for line in sys.path: print line    # print current python path

...


您可能希望__init__.py反驳一下,以弄清您的真实意思__init__.py,而不是init.py。只是为了避免使新手感到困惑。:)
antant

4

我知道这个线程有些陈旧,但是花了我一些时间才能真正理解这一点,所以我想分享一下。

在我的项目中,我的主脚本位于父目录中,为了区分模块,我将所有支持的模块放在一个称为“模块”的子文件夹中。在我的主脚本中,我像这样导入这些模块(对于名为report.py的模块):

from modules.report import report, reportError

如果我调用主脚本,则可以正常工作。但是,我想通过main()在每个模块中包含一个并直接调用每个模块来测试每个模块,如下所示:

python modules/report.py

现在,Python抱怨它找不到“称为模块的模块”。这里的关键是,默认情况下,Python在其搜索路径中包括脚本的文件夹,但不是CWD。因此,此错误实际上表示“我找不到模块子文件夹”。这是因为report.py模块所在的目录中没有“ modules”子目录。

我发现最巧妙的解决方案是通过在顶部包括以下内容来将CWD附加到Python搜索路径中:

import sys

sys.path.append(".")

现在,Python搜索CWD(当前目录),找到“模块”子文件夹,一切顺利。


3

我阅读了此问题以寻找答案,但不喜欢其中任何一个。

所以我写了一个快速而肮脏的解决方案。只需将其放在sys.path上的某个位置,它将在folder(来自当前工作目录)或下添加任何目录abspath

#using.py

import sys, os.path

def all_from(folder='', abspath=None):
    """add all dirs under `folder` to sys.path if any .py files are found.
    Use an abspath if you'd rather do it that way.

    Uses the current working directory as the location of using.py. 
    Keep in mind that os.walk goes *all the way* down the directory tree.
    With that, try not to use this on something too close to '/'

    """
    add = set(sys.path)
    if abspath is None:
        cwd = os.path.abspath(os.path.curdir)
        abspath = os.path.join(cwd, folder)
    for root, dirs, files in os.walk(abspath):
        for f in files:
            if f[-3:] in '.py':
                add.add(root)
                break
    for i in add: sys.path.append(i)

>>> import using, sys, pprint
>>> using.all_from('py') #if in ~, /home/user/py/
>>> pprint.pprint(sys.path)
[
#that was easy
]

我之所以喜欢它,是因为我可以为一些随机工具提供一个文件夹,而不必让它们成为软件包或任何东西的一部分,并且仍然可以通过几行代码访问其中的一些(或全部)。


3

我发现最简单的方法是创建一个文件“ any_name.pth”,并将其放在文件夹“ \ Lib \ site-packages”中。您应该在安装python的任何位置都找到该文件夹​​。

在该文件中,放入要保留要导入模块的目录列表。例如,在该文件中这样一行:

C:\ Users \ example ... \ example

您可以通过在python中运行它来告诉它工作:

import sys
for line in sys: print line

您将看到已打印的目录,以及从中可以导入的目录。现在,您可以轻松地导入该目录中的“ mymodule.py”文件:

import mymodule

这将不会导入子文件夹。为此,您可以想象创建一个python脚本来创建一个.pth文件,其中包含您定义的文件夹的所有子文件夹。让它在启动时运行。


0

旧问题的新选择。在Debian上
安装fail2ban软件包,看起来像是硬编码安装/usr/lib/python3/dist-packages/fail2ban在python3以外的路径上sys.path


> python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Jun 25 2019, 18:51:50)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/usr/lib/python3.7/site-packages']
>>>

因此,我(bash)将库链接到较新的版本,而不仅仅是复制。
将来对原始应用程序的更新也将自动应用于链接版本。

 if [ -d /usr/lib/python3/dist-packages/fail2ban ]
   then
      for d in /usr/lib/python3.*
      do
         [ -d ${d}/fail2ban ] || \
            ln -vs /usr/lib/python3/dist-packages/fail2ban ${d}/
      done
   fi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.