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

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

#!/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

这有点麻烦,难看,必须粘贴在每个文件的开头。还有更好的办法吗?

我真心希望能有这么光滑的东西:

#!/usr/bin/python
import sys.path
from os.path import pardir, sep
sys.path.append_relative(pardir + sep + "lib")


import mylib

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

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

这不会直接移植到非 posx 平台,但是可以保持整洁。

258973 次浏览

我用的是这个:

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

如果不想编辑每个文件

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

或者,如果您愿意为每个文件添加一行,则在 top (例如)处添加 import 语句。

import import_my_lib

import_my_lib.py保存在 bin 中,并且 import_my_lib可以正确地将 python 路径设置为任何您想要的 lib

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

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

然后你就可以用下面的代码来替换脚本顶部的所有东西:

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

如果您不希望以任何方式更改脚本内容,请将当前工作目录 .添加到 $PYTHONPATH (参见下面的示例)

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

今天就到此为止吧!

我在用:

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

每一个提供的答案都有一个问题,可以总结为“只要在你的剧本开头加上这个魔法咒语就行了。”。看看你能用一两行代码做些什么。”他们不会在任何可能的情况下工作!

例如,一个这样的魔法咒语使用 __file__。不幸的是,如果您使用 cx _ Frame 打包脚本,或者使用 IDLE,这将导致异常。

另一个这样的魔法咒语使用 os.getcwd ()。只有当你在命令提示符下运行你的脚本,并且包含你的脚本的目录是当前的工作目录(也就是说你在运行脚本之前使用 cd 命令切换到目录中) ,这个命令才会起作用。天啊!如果您的 Python 脚本在 PATH 中的某个地方,并且您只需键入脚本文件的名称就可以运行它,那么我希望我不必解释为什么这样做不起作用。

幸运的是,有一个魔法咒语可以在我测试过的所有案例中起作用。不幸的是,魔法咒语不仅仅是一两行代码。

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)

如你所见,这不是一件容易的事!

使用 python 3.4 +

import sys
from pathlib import Path


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


# Or as str as explained in https://stackoverflow.com/a/32701221/11043825
sys.path.append(str(Path(__file__).parent / "lib"))

您可以从相关的根目录中使用 python -m运行脚本,并将“模块路径”作为参数传递。

例子: $ python -m module.sub_module.main # Notice there is no '.py' at the end.


另一个例子:

$ tree  # Given this file structure
.
├── bar
│   ├── __init__.py
│   └── mod.py
└── foo
├── __init__.py
└── main.py


$ cat foo/main.py
from bar.mod import print1
print1()


$ cat bar/mod.py
def print1():
print('In bar/mod.py')


$ python foo/main.py  # This gives an error
Traceback (most recent call last):
File "foo/main.py", line 1, in <module>
from bar.mod import print1
ImportError: No module named bar.mod


$ python -m foo.main  # But this succeeds
In bar/mod.py

我在你的例子中看到了一个实例。如果您将 bin 脚本作为 ./bin/foo.py而不是 python ./bin/foo.py运行,那么可以选择使用 shebang 来更改 $PYTHONPATH变量。

但是,您不能直接在 shebang 中更改环境变量,因此需要一个小的 helper 脚本。将此 python.sh放入 bin文件夹:

#!/usr/bin/env bash
export PYTHONPATH=$PWD/lib
exec "/usr/bin/python" "$@"

然后把你的 ./bin/foo.py改成 #!bin/python.sh

当我们尝试使用终端的路径运行 python 文件时。

import sys
#For file name
file_name=sys.argv[0]
#For first argument
dir= sys.argv[1]
print("File Name: {}, argument dir: {}".format(file_name, dir)

保存文件(test.py)。

运行系统。

打开终端并转到保存文件的目录。 那就写吧

python test.py "/home/saiful/Desktop/bird.jpg"

按回车键

产出:

File Name: test, Argument dir: /home/saiful/Desktop/bird.jpg

我用:

from site import addsitedir

然后,可以使用任何相对目录! 这两个点意味着首先向上移动一个目录。

记住,这完全取决于你当前的工作目录。 如果 C: Joe Jen Becky,那么 Addsitedir (’. lib’)导入到路径 C: Joe Jen lib

C:\
|__Joe
|_ Jen
|     |_ Becky
|_ lib

这就是我多次的做法:

import os
import sys


current_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(current_path, "lib"))