如何获取当前执行的Python文件的路径和名称?

575 投票
26 回答
618163 浏览
提问于 2025-04-11 09:26

我有一些脚本会调用其他脚本文件,但我需要获取当前正在运行的文件的路径。

举个例子,假设我有三个文件。使用 execfile

  • script_1.py 调用 script_2.py
  • 然后,script_2.py 又调用 script_3.py

我该如何在script_3.py 中获取文件名和路径,而不需要从 script_2.py 传递这些信息作为参数呢?

(执行 os.getcwd() 会返回最开始启动的脚本的路径,而不是当前文件的路径。)

26 个回答

105

更新于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 fooimport lib.bar,不需要__init__.py文件。

也可以查看 导入和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

基于以下三个文件,并从其文件夹运行main.py,命令是python main.py(也尝试过使用绝对路径的execfiles和从其他文件夹调用)。

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
632
__file__

正如其他人所说,你可能还想使用 os.path.realpath 来消除符号链接:

import os

os.path.realpath(__file__)
286

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

撰写回答