Python: Best way to add to sys.path relative to the current running script
我有一个满是脚本的目录(比如
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 |
将
创建包装模块
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 |
如果不想以任何方式更改脚本内容,请将当前工作目录
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) |
正如你所看到的,这不是一项容易的任务!