Python:相对于当前运行脚本添加到sys.path的最佳方法

Python: Best way to add to sys.path relative to the current running script

我有一个满是脚本的目录(比如project/bin)。我还有一个位于project/lib的库,希望脚本自动加载它。这是我通常在每个脚本顶部使用的:

1
2
3
4
5
6
7
#!/usr/bin/python
from os.path import dirname, realpath, sep, pardir
import sys
sys.path.append(dirname(realpath(__file__)) + sep + pardir + sep +"lib")

# ... now the real code
import mylib

这有点麻烦,丑陋,必须粘贴在每个文件的开头。有更好的方法吗?

我真正希望的是像这样平滑的东西:

1
2
3
4
5
6
#!/usr/bin/python
import sys.path
from os.path import pardir, sep
sys.path.append_relative(pardir + sep +"lib")

import mylib

或者更好的是,当我的编辑器(或者其他有提交访问权的人)决定将导入重新排序作为其清理过程的一部分时,一些不会中断的内容:

1
2
#!/usr/bin/python --relpath_append ../lib
import mylib

这不会直接移植到非POSIX平台上,但会保持环境整洁。


这是我使用的:

1
2
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__),"lib"))


我正在使用:

1
2
import sys,os
sys.path.append(os.getcwd())


如果不想编辑每个文件

  • 像安装普通的python库一样安装库或
  • PYTHONPATH设置为lib

或者,如果您愿意为每个文件添加一行,请在顶部添加导入语句,例如

1
import import_my_lib

import_my_lib.py保留在bin中,import_my_lib可以将python路径正确设置为所需的lib路径。


创建包装模块project/bin/lib,其中包含:

1
2
3
4
5
6
7
8
import sys, os

sys.path.insert(0, os.path.join(
    os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib'))

import mylib

del sys.path[0], sys, os

然后,您可以将脚本顶部的所有cruft替换为:

1
2
#!/usr/bin/python
from lib import mylib

如果不想以任何方式更改脚本内容,请将当前工作目录.预先设置为$pythonpath(见下面的示例)

1
PYTHONPATH=.:$PYTHONPATH alembic revision --autogenerate -m"First revision"

今天就到此为止!


使用python 3.4+禁止使用cx_freeze或在空闲时使用。???

1
2
3
4
import sys
from pathlib import Path

sys.path.append(Path(__file__).parent /"lib")


每一个答案都有一个问题,只要你的剧本开头加上这个神奇的咒语就可以了。看看你能用一两行代码来做什么。"它们不会在任何可能的情况下都起作用!

例如,一个这样的魔法咒语使用文件。不幸的是,如果您使用cx-freeze打包脚本或使用idle,这将导致异常。

另一种魔法咒语使用os.getcwd()。只有在从命令提示符运行脚本时,并且包含脚本的目录是当前工作目录(即在运行脚本之前使用cd命令更改到目录中),此操作才有效。上帝啊!我希望我不必解释为什么如果您的Python脚本位于某个路径中,并且您只需键入脚本文件的名称就可以运行它,那么这将不起作用。

幸运的是,有一种神奇的咒语可以在我测试过的所有情况下使用。不幸的是,魔法咒语不仅仅是一两行代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import inspect
import os
import sys

# Add script directory to sys.path.
# This is complicated due to the fact that __file__ is not always defined.

def GetScriptDirectory():
    if hasattr(GetScriptDirectory,"dir"):
        return GetScriptDirectory.dir
    module_path =""
    try:
        # The easy way. Just use __file__.
        # Unfortunately, __file__ is not available when cx_freeze is used or in IDLE.
        module_path = __file__
    except NameError:
        if len(sys.argv) > 0 and len(sys.argv[0]) > 0 and os.path.isabs(sys.argv[0]):
            module_path = sys.argv[0]
        else:
            module_path = os.path.abspath(inspect.getfile(GetScriptDirectory))
            if not os.path.exists(module_path):
                # If cx_freeze is used the value of the module_path variable at this point is in the following format.
                # {PathToExeFile}\{NameOfPythonSourceFile}. This makes it necessary to strip off the file name to get the correct
                # path.
                module_path = os.path.dirname(module_path)
    GetScriptDirectory.dir = os.path.dirname(module_path)
    return GetScriptDirectory.dir

sys.path.append(os.path.join(GetScriptDirectory(),"lib"))
print(GetScriptDirectory())
print(sys.path)

正如你所看到的,这不是一项容易的任务!