我有调用其他脚本文件的脚本,但我需要获取当前在进程中运行的文件的文件路径。
例如,假设我有三个文件。使用 execfile:
script_1.py 调用 script_2.py。
反过来,script_2.py 调用 script_3.py。
如何从 script_3.py
内的代码中获取 script_3.py
的文件名和路径,而无需将这些信息作为参数从 script_2.py
传递?
(执行 os.getcwd()
返回原始启动脚本的文件路径,而不是当前文件的。)
p1.py:
execfile("p2.py")
p2.py:
import inspect, os
print (inspect.getfile(inspect.currentframe())) # script filename (usually with path)
print (os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) # script directory
inspect.getabsfile()
,它适用于我尝试过的所有案例。
os.path.realpath(__file__)
inspect.getfile()
如果传递了模块对象,则返回 __file__
属性。 inspect.currentframe()
返回模块。因此,这是一种昂贵的说法 __file__
。
2018 年 11 月 28 日更新:
这是 Python 2 和 3 的实验总结。
main.py - 运行 foo.py foo.py - 运行 lib/bar.py lib/bar.py - 打印文件路径表达式
| Python | Run statement | Filepath expression |
|--------+---------------------+----------------------------------------|
| 2 | execfile | os.path.abspath(inspect.stack()[0][1]) |
| 2 | from lib import bar | __file__ |
| 3 | exec | (wasn't able to obtain it) |
| 3 | import lib.bar | __file__ |
对于 Python 2,切换到包以便使用 from lib import bar
可能更清楚 - 只需将空 __init__.py
文件添加到这两个文件夹。
对于 Python 3,execfile
不存在 - 最接近的替代方案是 exec(open(<filename>).read())
,尽管这会影响堆栈帧。只使用 import foo
和 import lib.bar
是最简单的 - 不需要 __init__.py
文件。
另请参阅Difference between import and execfile
原答案:
这是基于此线程中答案的实验 - 在 Windows 上使用 Python 2.7.10。
基于堆栈的那些是唯一似乎给出可靠结果的。最后两个具有最短的语法,即 -
print os.path.abspath(inspect.stack()[0][1]) # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1])) # C:\filepaths\lib
这是将这些作为函数添加到 sys 的内容!感谢@Usagi 和@pablog
基于以下三个文件,并使用 python main.py
从其文件夹中运行 main.py(还尝试了使用绝对路径的 execfile 并从单独的文件夹中调用)。
C:\filepaths\main.py: execfile('foo.py')
C:\filepaths\foo.py: execfile('lib/bar.py')
C:\filepaths\lib\bar.py:
import sys
import os
import inspect
print "Python " + sys.version
print
print __file__ # main.py
print sys.argv[0] # main.py
print inspect.stack()[0][1] # lib/bar.py
print sys.path[0] # C:\filepaths
print
print os.path.realpath(__file__) # C:\filepaths\main.py
print os.path.abspath(__file__) # C:\filepaths\main.py
print os.path.basename(__file__) # main.py
print os.path.basename(os.path.realpath(sys.argv[0])) # main.py
print
print sys.path[0] # C:\filepaths
print os.path.abspath(os.path.split(sys.argv[0])[0]) # C:\filepaths
print os.path.dirname(os.path.abspath(__file__)) # C:\filepaths
print os.path.dirname(os.path.realpath(sys.argv[0])) # C:\filepaths
print os.path.dirname(__file__) # (empty string)
print
print inspect.getfile(inspect.currentframe()) # lib/bar.py
print os.path.abspath(inspect.getfile(inspect.currentframe())) # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # C:\filepaths\lib
print
print os.path.abspath(inspect.stack()[0][1]) # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1])) # C:\filepaths\lib
print
我认为这更清洁:
import inspect
print inspect.stack()[0][1]
并获得与以下相同的信息:
print inspect.getfile(inspect.currentframe())
其中 [0] 是堆栈中的当前帧(堆栈顶部),[1] 是文件名,增加以在堆栈中向后移动,即
print inspect.stack()[1][1]
将是调用当前帧的脚本的文件名。此外,使用 [-1] 将使您到达堆栈的底部,即原始调用脚本。
inspect.getfile()
如果传递了模块对象,则返回 __file__
属性。 inspect.currentframe()
返回模块。因此,这是一种昂贵的说法 __file__
。
inspect.stack()
是一个非常昂贵的函数,不仅仅是 inspect.currentframe()
,而且它也在模块对象上调用 inspect.getfile()
。
import os
os.path.dirname(__file__) # relative directory path
os.path.abspath(__file__) # absolute file path
os.path.basename(__file__) # the file name only
__file__
获取文件名。
os.path.dirname
将为您提供运行脚本的相对路径。例如,在 python ../../test.py
中,os.path.dirname
将是 ../../
,而不是脚本的绝对路径。我正在寻找 abspath 但删除了脚本的名称。 sys.path 的第一个元素显然是答案 sys.path[0]
。
如果您的脚本仅包含一个文件,则标记为最佳的建议都是正确的。
如果您想从可能作为模块导入的文件中找出可执行文件的名称(即传递给当前程序的python解释器的根文件),您需要这样做(假设这是在一个文件中命名为 foo.py):
import inspect
print inspect.stack()[-1][1]
因为堆栈上的最后一件事 ([-1]
) 是进入其中的第一件事(堆栈是 LIFO/FILO 数据结构)。
然后在文件 bar.py 中,如果您import foo
,它将打印 bar.py,而不是 foo.py,这将是所有这些的价值:
__文件__
inspect.getfile(inspect.currentframe())
检查.stack()[0][1]
sys.modules['__main__'].__file__
的方式,真的。
由于 Python 3 相当主流,因此我想包含一个 pathlib
答案,因为我相信它现在可能是访问文件和路径信息的更好工具。
from pathlib import Path
current_file: Path = Path(__file__).resolve()
如果要查找当前文件的目录,只需将 .parent
添加到 Path()
语句即可:
current_path: Path = Path(__file__).parent.resolve()
“当前在进程中运行的文件的文件路径”是什么意思并不完全清楚。 sys.argv[0]
通常包含 Python 解释器调用的脚本的位置。查看 sys documentation 了解更多详情。
正如@Tim 和@Pat Notz 所指出的, __file__ 属性提供了对
加载模块的文件,如果它是从文件加载的
import os
print os.path.basename(__file__)
这只会给我们文件名。即如果文件的绝对路径是 c:\abcd\abc.py 那么第二行将打印 abc.py
我有一个必须在 windows 环境下工作的脚本。这段代码是我完成的:
import os,sys
PROJECT_PATH = os.path.abspath(os.path.split(sys.argv[0])[0])
这是一个很老套的决定。但它不需要外部库,这对我来说是最重要的。
尝试这个,
import os
os.path.dirname(os.path.realpath(__file__))
import os
os.path.dirname(os.path.abspath(__file__))
无需检查或任何其他库。
当我必须导入一个脚本(从不同的目录然后是执行的脚本)时,这对我有用,该脚本使用与导入脚本位于同一文件夹中的配置文件。
__file__
属性适用于包含主要执行代码的文件以及导入的模块。
请参阅https://web.archive.org/web/20090918095828/http://pyref.infogami.com/__file__
import sys
print sys.path[0]
这将打印当前执行脚本的路径
您可以使用 inspect.stack()
import inspect,os
inspect.stack()[0] => (<frame object at 0x00AC2AC0>, 'g:\\Python\\Test\\_GetCurrentProgram.py', 15, '<module>', ['print inspect.stack()[0]\n'], 0)
os.path.abspath (inspect.stack()[0][1]) => 'g:\\Python\\Test\\_GetCurrentProgram.py'
import sys
print sys.argv[0]
print(__file__)
print(__import__("pathlib").Path(__file__).parent)
这应该有效:
import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
这是我使用的,所以我可以毫无问题地将我的代码扔到任何地方。 __name__
始终被定义,但 __file__
仅在代码作为文件运行时才定义(例如,不在 IDLE/iPython 中)。
if '__file__' in globals():
self_name = globals()['__file__']
elif '__file__' in locals():
self_name = locals()['__file__']
else:
self_name = __name__
或者,这可以写成:
self_name = globals().get('__file__', locals().get('__file__', __name__))
获取执行脚本的目录
print os.path.dirname( inspect.getfile(inspect.currentframe()))
我使用 __file__
os.path.abspath(__file__)
的方法,但有一个小技巧,它在第一次运行代码时返回 .py 文件,下一次运行给出 *.pyc 文件的名称
所以我留在了:
inspect.getfile(inspect.currentframe())
或
sys._getframe().f_code.co_filename
我写了一个考虑到eclipse调试器和unittest的函数。它返回您启动的第一个脚本的文件夹。您可以选择指定 __file__ 变量,但主要是您不必在所有调用层次结构中共享此变量。
也许你可以处理我没有看到的其他堆栈特殊情况,但对我来说没关系。
import inspect, os
def getRootDirectory(_file_=None):
"""
Get the directory of the root execution file
Can help: http://stackoverflow.com/questions/50499/how-do-i-get-the-path-and-name-of-the-file-that-is-currently-executing
For eclipse user with unittest or debugger, the function search for the correct folder in the stack
You can pass __file__ (with 4 underscores) if you want the caller directory
"""
# If we don't have the __file__ :
if _file_ is None:
# We get the last :
rootFile = inspect.stack()[-1][1]
folder = os.path.abspath(rootFile)
# If we use unittest :
if ("/pysrc" in folder) & ("org.python.pydev" in folder):
previous = None
# We search from left to right the case.py :
for el in inspect.stack():
currentFile = os.path.abspath(el[1])
if ("unittest/case.py" in currentFile) | ("org.python.pydev" in currentFile):
break
previous = currentFile
folder = previous
# We return the folder :
return os.path.dirname(folder)
else:
# We return the folder according to specified __file__ :
return os.path.dirname(os.path.realpath(_file_))
最简单的方法是:
在 script_1.py 中:
import subprocess
subprocess.call(['python3',<path_to_script_2.py>])
在 script_2.py 中:
sys.argv[0]
PS:我尝试过 execfile
,但由于它将 script_2.py 读取为字符串,因此 sys.argv[0]
返回了 <string>
。
以下返回当前主脚本所在的路径。我用 Linux、Win10、IPython 和 Jupyter Lab 对此进行了测试。我需要一个也适用于本地 Jupyter 笔记本的解决方案。
import builtins
import os
import sys
def current_dir():
if "get_ipython" in globals() or "get_ipython" in dir(builtins):
# os.getcwd() is PROBABLY the dir that hosts the active notebook script.
# See also https://github.com/ipython/ipython/issues/10123
return os.getcwd()
else:
return os.path.abspath(os.path.dirname(sys.argv[0]))
不定期副业成功案例分享
__file__
返回“script_name.py”,有时返回“script_name.pyc”。所以输出不稳定。"__file__"
运行时,引号(作为字符串)给出了运行 cmd 的目录,但是__file__
(不带引号给出了源文件的路径......为什么会这样os.path.realpath
函数假定路径的dir
部分的内容。os.path.dirname(os.path.realpath(__file__))
返回文件所在的目录。os.path.dirname(os.path.realpath("__file__"))
返回 cwd。os.path.dirname(os.path.realpath("here_be_dragons"))
也返回 cwd。