Python 如何正确确定当前脚本目录?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3718657/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to properly determine current script directory?
提问by bogdan
I would like to see what is the best way to determine the current script directory in python?
我想看看在 python 中确定当前脚本目录的最佳方法是什么?
I discovered that, due to the many ways of calling python code, it is hard to find a good solution.
我发现,由于调用python代码的方式很多,很难找到一个好的解决方案。
Here are some problems:
这里有一些问题:
__file__is not defined if the script is executed withexec,execfile__module__is defined only in modules
__file__如果使用exec,执行脚本,则未定义execfile__module__仅在模块中定义
Use cases:
用例:
./myfile.pypython myfile.py./somedir/myfile.pypython somedir/myfile.pyexecfile('myfile.py')(from another script, that can be located in another directory and that can have another current directory.
./myfile.pypython myfile.py./somedir/myfile.pypython somedir/myfile.pyexecfile('myfile.py')(来自另一个脚本,它可以位于另一个目录中,并且可以有另一个当前目录。
I know that there is no perfect solution, but I'm looking for the best approach that solves most of the cases.
我知道没有完美的解决方案,但我正在寻找解决大多数情况的最佳方法。
The most used approach is os.path.dirname(os.path.abspath(__file__))but this really doesn't work if you execute the script from another one with exec().
最常用的方法是,os.path.dirname(os.path.abspath(__file__))但是如果您从另一个使用exec().
Warning
警告
Any solution that uses current directory will fail, this can be different based on the way the script is called or it can be changed inside the running script.
任何使用当前目录的解决方案都将失败,这可能会因调用脚本的方式而异,或者可以在运行脚本中进行更改。
回答by Will McCutchen
Would
将
import os
cwd = os.getcwd()
do what you want? I'm not sure what exactly you mean by the "current script directory". What would the expected output be for the use cases you gave?
做你想做的事?我不确定“当前脚本目录”究竟是什么意思。您提供的用例的预期输出是什么?
回答by bobince
os.path.dirname(os.path.abspath(__file__))
is indeed the best you're going to get.
确实是你要得到的最好的。
It's unusual to be executing a script with exec/execfile; normally you should be using the module infrastructure to load scripts. If you must use these methods, I suggest setting __file__in the globalsyou pass to the script so it can read that filename.
使用exec/执行脚本是不寻常的execfile;通常您应该使用模块基础结构来加载脚本。如果您必须使用这些方法,我建议您在传递给脚本的文件中进行设置__file__,globals以便它可以读取该文件名。
There's no other way to get the filename in execed code: as you note, the CWD may be in a completely different place.
没有其他方法可以在执行代码中获取文件名:正如您所注意到的,CWD 可能位于完全不同的位置。
回答by Sven Marnach
If you really want to cover the case that a script is called via execfile(...), you can use the inspectmodule to deduce the filename (including the path). As far as I am aware, this will work for all cases you listed:
如果您真的想涵盖通过 调用脚本的情况execfile(...),您可以使用该inspect模块来推断文件名(包括路径)。据我所知,这适用于您列出的所有情况:
filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
回答by wim
Just use os.path.dirname(os.path.abspath(__file__))and examine very carefully whether there is a real need for the case where execis used. It could be a sign of troubled design if you are not able to use your script as a module.
只是在使用os.path.dirname(os.path.abspath(__file__))的情况下非常仔细地使用和检查是否真的需要使用的情况exec。如果您无法将脚本用作模块,则可能是设计有问题的迹象。
Keep in mind Zen of Python #8, and if you believe there is a good argument for a use-case where it must work for exec, then please let us know some more details about the background of the problem.
请记住Python #8 的 Zen,如果您认为它必须适用于的用例有很好的论据exec,那么请让我们了解有关问题背景的更多详细信息。
回答by synthesizerpatel
First.. a couple missing use-cases here if we're talking about ways to inject anonymous code..
首先..如果我们在谈论注入匿名代码的方法,这里有几个缺少的用例..
code.compile_command()
code.interact()
imp.load_compiled()
imp.load_dynamic()
imp.load_module()
__builtin__.compile()
loading C compiled shared objects? example: _socket?)
But, the real question is, what is your goal - are you trying to enforce some sort of security? Or are you just interested in whats being loaded.
但是,真正的问题是,您的目标是什么——您是否试图强制执行某种安全措施?或者您只是对正在加载的内容感兴趣。
If you're interested in security, the filename that is being imported via exec/execfile is inconsequential - you should use rexec, which offers the following:
如果您对security感兴趣,则通过 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.
该模块包含 RExec 类,该类支持 r_eval()、r_execfile()、r_exec() 和 r_import() 方法,这些方法是标准 Python 函数 eval()、execfile() 以及 exec 和 import 语句的受限版本。在这个受限环境中执行的代码只能访问被认为安全的模块和功能;您可以根据需要为 RExec 添加或删除功能子类。
However, if this is more of an academic pursuit.. here are a couple goofy approaches that you might be able to dig a little deeper into..
但是,如果这更像是一种学术追求……这里有一些愚蠢的方法,您可以深入研究一下……
Example scripts:
示例脚本:
./deep.py
./deep.py
print ' >> level 1'
execfile('deeper.py')
print ' << level 1'
./deeper.py
./deeper.py
print '\t >> level 2'
exec("import sys; sys.path.append('/tmp'); import deepest")
print '\t << level 2'
/tmp/deepest.py
/tmp/deepest.py
print '\t\t >> level 3'
print '\t\t\t I can see the earths core.'
print '\t\t << level 3'
./codespy.py
./codespy.py
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)
Output
输出
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
Of course, this is a resource-intensive way to do it, you'd be tracing all your code.. Not very efficient. But, I think it's a novel approach since it continues to work even as you get deeper into the nest. You can't override 'eval'. Although you canoverride execfile().
当然,这是一种资源密集型的方法,您将跟踪所有代码......效率不高。但是,我认为这是一种新颖的方法,因为即使您深入巢穴,它仍然可以继续工作。你不能覆盖'eval'。尽管您可以覆盖 execfile()。
Note, this approach only coveres exec/execfile, not 'import'. For higher level 'module' load hooking you might be able to use use sys.path_hooks(Write-up courtesy of PyMOTW).
请注意,此方法仅涵盖 exec/execfile,而不是“导入”。对于更高级别的“模块”负载挂钩,您可以使用 sys.path_hooks(由 PyMOTW 提供)。
Thats all I have off the top of my head.
这就是我头顶上的全部。
回答by sorin
Here is a partial solution, still better than all published ones so far.
这是一个部分解决方案,仍然比迄今为止所有已发布的解决方案要好。
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__))
Now this works will all calls but if someone use chdir()to change the current directory, this will also fail.
现在这将适用于所有调用,但如果有人chdir()用来更改当前目录,这也将失败。
Notes:
笔记:
sys.argv[0]is not going to work, will return-cif you execute the script withpython -c "execfile('path-tester.py')"- I published a complete test at https://gist.github.com/1385555and you are welcome to improve it.
sys.argv[0]不会工作,-c如果你执行脚本会返回python -c "execfile('path-tester.py')"- 我在https://gist.github.com/1385555发布了一个完整的测试,欢迎您改进它。
回答by jfs
#!/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())
It works on CPython, Jython, Pypy. It works if the script is executed using execfile()(sys.argv[0]and __file__-based solutions would fail here). It works if the script is inside an executable zip file (/an egg). It works if the script is "imported" (PYTHONPATH=/path/to/library.zip python -mscript_to_run) from a zip file; it returns the archive path in this case. It works if the script is compiled into a standalone executable (sys.frozen). It works for symlinks (realpatheliminates symbolic links). It works in an interactive interpreter; it returns the current working directory in this case.
它适用于 CPython、Jython、Pypy。如果使用execfile()(sys.argv[0]和__file__-based 解决方案将在这里失败)执行脚本,它就可以工作。如果脚本在一个可执行的 zip 文件 (/an egg) 中,它就可以工作。如果脚本是PYTHONPATH=/path/to/library.zip python -mscript_to_run从 zip 文件“导入” ( ) 的,则它有效;在这种情况下,它返回存档路径。如果脚本被编译成独立的可执行文件 ( sys.frozen),它就可以工作。它适用于符号链接(realpath消除符号链接)。它在交互式解释器中工作;在这种情况下,它返回当前工作目录。
回答by Jahid
This should work in most cases:
这在大多数情况下应该有效:
import os,sys
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
回答by Mark
Hopefully this helps:-
If you run a script/module from anywhere you'll be able to access the __file__variable which is a module variable representing the location of the script.
希望这会有所帮助:- 如果您从任何地方运行脚本/模块,您将能够访问__file__变量,该变量是表示脚本位置的模块变量。
On the other hand, if you're using the interpreter you don't have access to that variable, where you'll get a name NameErrorand os.getcwd()will give you the incorrect directory if you're running the file from somewhere else.
另一方面,如果您使用的是解释器,则您无权访问该变量,如果您从其他地方运行该文件,您将在其中获得一个名称NameError并os.getcwd()为您提供不正确的目录。
Thissolution should give you what you're looking for in all cases:
在所有情况下,此解决方案都应为您提供所需的内容:
from inspect import getsourcefile
from os.path import abspath
abspath(getsourcefile(lambda:0))
I haven't thoroughly tested it but it solved my problem.
我还没有彻底测试它,但它解决了我的问题。

