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

Python:相对于当前运行的脚本添加到sys.path的最佳方法,python,python-import,Python,Python Import,我有一个满是脚本的目录(比如说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 re

我有一个满是脚本的目录(比如说
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
这不会直接移植到非posix平台,但会保持整洁。

我使用的是:

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

如果不想编辑每个文件

  • 像安装普通python库一样安装库
  • PYTHONPATH
    设置为您的
    lib
或者,如果您愿意为每个文件添加一行,请在顶部添加导入语句,例如

import import_my_lib

在bin中保留
import\u my_lib.py
,并且
import\u my_lib
可以正确地将python路径设置为所需的任何
lib

创建包装器模块
项目/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(请参见下面的示例)

今天到此为止

我正在使用:

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

提供的每个答案都有一个问题,可以概括为“只需在脚本开头添加这个神奇的咒语。看看你能用一两行代码做些什么。”它们不会在所有可能的情况下都起作用

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

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

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

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

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

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

示例:
$python-m module.sub_module.main#注意末尾没有“.py”。


另一个例子:

$ 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
$tree#给定此文件结构
.
├── 酒吧
│   ├── __初始值
│   └── mod.py
└── 福
├── __初始值
└── main.py
$cat foo/main.py
从bar.mod导入打印1
print1()
$cat bar/mod.py
def print1():
打印('bar/mod.py')
$python foo/main.py#这会给出一个错误
回溯(最近一次呼叫最后一次):
文件“foo/main.py”,第1行,在
从bar.mod导入打印1
ImportError:没有名为bar.mod的模块
$python-mfoo.main#但这成功了
单位:bar/mod.py

我在您的示例中看到一个shebang。如果您以
/bin/foo.py
而不是
python./bin/foo.py
的形式运行bin脚本,那么可以使用shebang来更改
$PYTHONPATH
变量

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

#/usr/bin/env bash
导出PYTHONPATH=$PWD/lib
exec“/usr/bin/python”“$@”

然后将
/bin/foo.py
的shebang更改为
#!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
我使用:

然后,可以使用任何相对目录!
addsitedir('..\lib')
;这两点表示先(向上)移动一个目录

请记住,这完全取决于当前工作目录的起始位置。 如果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"))

另请参见:“sys.path是从以下位置初始化的:-包含输入脚本的目录”。我认为这不是真的。我倾向于这样做,尤其是在.envrc中,这样对于direnv,它甚至是自动的和隔离的。我会执行sys.path.insert(0,…),这样它就不会被其他路径覆盖。真的没有办法让它自动运行吗?这有点风险。如果
\uuuu file\uuuu
是相对于当前工作目录的相对文件名(例如,
setup.py
),则
os.path.dirname(\uuu file\uuuu)
将是空字符串。对于这一点,'s是非常可取的。我通常只执行
sys.path.append('.')
如果脚本是从其他目录运行的呢?例如,通过提供完整的系统路径,从根目录开始?然后os.getcwd()将返回“/”永远不要这样做。当前的工作目录(CWD)不能保证是您认为的那样——特别是在不可预见的边缘情况下,您肯定应该在一英里之外看到它。只需参考
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
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"))