How to properly determine current script directory?
我想看看在python中确定当前脚本目录的最佳方法是什么?
我发现,由于调用Python代码的方式很多,很难找到一个好的解决方案。
以下是一些问题:
- 如果脚本使用
exec 和execfile 执行,则不定义__file__ 。 __module__ 仅在模块中定义。
用例:
./myfile.py python myfile.py ./somedir/myfile.py python somedir/myfile.py execfile('myfile.py') (来自另一个脚本,可以位于另一个目录中,也可以具有另一个当前目录。
我知道没有完美的解决方案,但我正在寻找解决大多数情况的最佳方法。
最常用的方法是
任何使用当前目录的解决方案都将失败,这可能与调用脚本的方式不同,也可能在正在运行的脚本中进行更改。
1 | os.path.dirname(os.path.abspath(__file__)) |
确实是你能得到的最好的。
使用
没有其他方法可以在执行代码中获取文件名:正如您所注意到的,CWD可能位于完全不同的位置。
如果您真的想覆盖通过
1 2 | filename = inspect.getframeinfo(inspect.currentframe()).filename path = os.path.dirname(os.path.abspath(filename)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!/usr/bin/env python import inspect import os import sys def get_script_dir(follow_symlinks=True): if getattr(sys, 'frozen', False): # py2exe, PyInstaller, cx_Freeze path = os.path.abspath(sys.executable) else: path = inspect.getabsfile(get_script_dir) if follow_symlinks: path = os.path.realpath(path) return os.path.dirname(path) print(get_script_dir()) |
它适用于cpython,jython,pypy。如果使用
在python 3.4+中,可以使用更简单的
1 2 3 4 5 | from inspect import currentframe, getframeinfo from pathlib import Path filename = getframeinfo(currentframe()).filename parent = Path(filename).resolve().parent |
只需使用
请记住python 8的zen,如果您认为对于一个必须适用于
在python 2中,
在python 3中,可以找到如下脚本目录:
1 2 | from pathlib import Path cwd = Path(__file__).parents[0] |
第一。。如果我们在讨论注入匿名代码的方法,这里会有一些遗漏的用例。
1 2 3 4 5 6 7 | code.compile_command() code.interact() imp.load_compiled() imp.load_dynamic() imp.load_module() __builtin__.compile() loading C compiled shared objects? example: _socket?) |
但是,真正的问题是,你的目标是什么——你是否试图加强某种安全?或者你只是对正在加载的内容感兴趣。
如果您对安全感兴趣,通过exec/execfile导入的文件名是不合理的-您应该使用rexec,它提供以下功能:
This module contains the RExec class,
which supports r_eval(), r_execfile(),
r_exec(), and r_import() methods, which
are restricted versions of the standard
Python functions eval(), execfile() and
the exec and import statements. Code
executed in this restricted environment
will only have access to modules and
functions that are deemed safe; you can
subclass RExec add or remove capabilities as
desired.
然而,如果这更像是一种学术追求……以下是一些愚蠢的方法也许能更深入地挖掘……
示例脚本:
。
1 2 3 | print ' >> level 1' execfile('deeper.py') print ' << level 1' |
/深度
1 2 3 | print '\t >> level 2' exec("import sys; sys.path.append('/tmp'); import deepest") print '\t << level 2' |
/tMP/DePiSt.Py
1 2 3 | print '\t\t >> level 3' print '\t\t\t I can see the earths core.' print '\t\t << level 3' |
/CODESPY.PY
1 2 3 4 5 6 7 8 | import sys, os def overseer(frame, event, arg): print"loaded(%s)" % os.path.abspath(frame.f_code.co_filename) sys.settrace(overseer) execfile("deep.py") sys.exit(0) |
产量
1 2 3 4 5 6 7 8 9 10 11 | loaded(/Users/synthesizerpatel/deep.py) >> level 1 loaded(/Users/synthesizerpatel/deeper.py) >> level 2 loaded(/Users/synthesizerpatel/<string>) loaded(/tmp/deepest.py) >> level 3 I can see the earths core. << level 3 << level 2 << level 1 |
当然,这是一种资源密集型的方法,您将跟踪所有代码..效率不是很高。但是,我认为这是一种新颖的方法因为它会继续工作,即使你进入巢穴的深处。不能覆盖"eval"。尽管可以重写execfile()。
注意,这种方法只覆盖exec/execfile,而不是"import"。对于更高级别的"模块"负载挂钩,您可能可以使用系统路径挂钩(由Pymotw提供)。
这就是我头上的所有东西。
1 2 3 4 5 6 7 8 9 | import os import sys def get_script_path(): return os.path.dirname(os.path.realpath(sys.argv[0])) my_script_dir = get_script_path() print my_script_dir |
这为您提供了位于堆栈顶部的脚本目录(即正在执行的脚本,而不是通常第一次执行的python的,返回
这在大多数情况下都会起作用:
1 2 | import os,sys dirname=os.path.dirname(os.path.realpath(sys.argv[0])) |
这里有一个部分的解决方案,仍然比目前所有已发布的解决方案都好。
1 2 3 4 5 6 7 8 | import sys, os, os.path, inspect #os.chdir("..") if '__file__' not in locals(): __file__ = inspect.getframeinfo(inspect.currentframe())[0] print os.path.dirname(os.path.abspath(__file__)) |
现在所有的调用都能正常工作,但是如果有人使用
笔记:
- 如果用
python -c"execfile('path-tester.py')" 执行脚本,sys.argv[0] 将不工作,返回-c 。 - 我在https://gist.github.com/1385555上发布了一个完整的测试,欢迎您改进它。
希望这有助于:如果从任何地方运行脚本/模块,则可以访问
另一方面,如果您使用的是解释器,那么您没有访问该变量的权限,在该变量中,您将得到一个名称
在所有情况下,此解决方案都应为您提供所需的功能:
1 2 3 | from inspect import getsourcefile from os.path import abspath abspath(getsourcefile(lambda:0)) |
我没有彻底测试过,但它解决了我的问题。
会
1 2 | import os cwd = os.getcwd() |
做你想做的?我不知道"当前脚本目录"究竟是什么意思。对于您提供的用例,预期的输出是什么?
就1号[6号]在Jupyter笔记本电脑上: