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

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

python someprojectfile.py

我明白

ImportError: no module named core.'somemodule'

对于所有的导入,我假设这是路径的一个问题。

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

270342 次浏览

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

  • 将环境变量 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通常是最好的方法。

然而,当你使用的东西只是运行在你自己的电脑上(或者当你有非标准的设置,例如有时在网络应用程序框架中) ,这并不是完全不寻常的事情,这样做呢

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

您还应该在这里阅读有关 python 包的内容: http://docs.python.org/tutorial/modules.html

从你的例子中,我猜想你真的有一个包在 ~/codez/project。Python 目录中的文件 __init__.py将目录映射到命名空间。如果您的子目录都有一个 __init__.py文件,那么您只需要将基目录添加到 PYTHONPATH。例如:

PYTHONPATH = $PYTHONPATH: $HOME/adaifotis/project

除了测试你的 pythonPATh 环境变量,正如大卫解释的那样,你也可以像这样在 python 中测试它:

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

...

我读这个问题是为了寻找答案,但是没有一个答案是我喜欢的。

所以我写了一个又快又脏的解决方案。只要把它放在 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
]

我喜欢它是因为我可以为一些随机的工具建立一个文件夹,而不是让它们成为包或其他东西的一部分,并且仍然可以在几行代码中访问它们中的一些(或全部)。

我发现最简单的方法是创建一个文件 any_name.pth,并把它放在您的文件夹 \Lib\site-packages。您应该在安装 python 的位置找到该文件夹。

在该文件中,列出要保存用于导入的模块的目录。例如,在那个文件中写一行如下:

C:\Users\example\...\example

您可以通过在 python 中运行这个命令来判断它的工作原理:

import sys
for line in sys.path:
print line

您将看到您的目录被打印出来,还有其他一些目录,您也可以从这些目录中导入。现在,您可以轻松地导入位于该目录中的 mymodule.py文件,如下所示:

import mymodule

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

我知道这个帖子有点老了,但是我花了一些时间才弄清楚这个问题的核心,所以我想和大家分享一下。

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

from modules.report import report, reportError

如果我调用我的主要脚本,这个工程。然而,我想通过在每个模块中包含一个 main()并直接调用每个模块来测试每个模块,如下所示:

python modules/report.py

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

我发现最简洁的解决方案是在 Python 搜索路径中附加 CWD,方法是在顶部包含以下内容:

import sys


sys.path.append(".")

现在,Python 搜索 CWD (工作目录) ,找到“ module”子文件夹,一切正常。

旧问题的新选项。
在 Debian 上安装 fail2ban软件包,在 /usr/lib/python3/dist-packages/fail2ban上安装一个不在 python3sys.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)将库链接到更新的版本,而不仅仅是复制。< br > 未来对原始应用程序的更新,也将自动应用到链接版本。

 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

第一个任务是找出当前环境的标准库是从哪里来的。这就是我存储 OOP 模块的地方。

Import numpy


numpy.__file__

您可以获得环境的目录。对于另一台计算机,最好为 OOP 模块创建一个单独的目录。

Import sys


sys.path.append('F:/Python/My_libra/')