ChatGPT解决这个技术问题 Extra ChatGPT

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

我有调用其他脚本文件的脚本,但我需要获取当前在进程中运行的文件的文件路径。

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

script_1.py 调用 script_2.py。

反过来,script_2.py 调用 script_3.py。

如何从 script_3.py 内的代码中获取 script_3.py 的文件名和路径,而无需将这些信息作为参数从 script_2.py 传递?

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


C
Cees Timmerman
__file__

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

import os

os.path.realpath(__file__)

使用这种方法需要小心,因为有时 __file__ 返回“script_name.py”,有时返回“script_name.pyc”。所以输出不稳定。
但是因为我们只使用了这个无关紧要的文件的路径。
这很奇怪:当从命令行 "__file__" 运行时,引号(作为字符串)给出了运行 cmd 的目录,但是 __file__(不带引号给出了源文件的路径......为什么会这样
@muon 没有检查传入的文件名字符串是否存在,并且由于文件路径是相对于 cwd 的,这就是 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。
k
kjo

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

注意:此调用不会在不同的环境中给出相同的结果。考虑在下面接受 Usagi 的回答:stackoverflow.com/a/6628348/851398
@faraday:你能举个例子吗?我已经回答了 similar question using inspect.getabsfile(),它适用于我尝试过的所有案例。
不,user13993 做得更好
user13993 确实做到了。应该是 os.path.realpath(__file__)
inspect.getfile() 如果传递了模块对象,则返回 __file__ 属性。 inspect.currentframe() 返回模块。因此,这是一种昂贵的说法 __file__
B
Brian Burns

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 文件。

另请参阅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

U
Usagi

我认为这更清洁:

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()
N
Neal Xiong
import os
os.path.dirname(__file__) # relative directory path
os.path.abspath(__file__) # absolute file path
os.path.basename(__file__) # the file name only

我刚试过@Pat Notz 的评论。我认为您可以通过 __file__ 获取文件名。
在 Python3 中,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]


它运行良好,但不适用于 Eclipse 上的单元测试,我得到了 /home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc
这是一种昂贵的拼写 sys.modules['__main__'].__file__ 的方式,真的。
D
Doug

由于 Python 3 相当主流,因此我想包含一个 pathlib 答案,因为我相信它现在可能是访问文件和路径信息的更好工具。

from pathlib import Path

current_file: Path = Path(__file__).resolve()

如果要查找当前文件的目录,只需将 .parent 添加到 Path() 语句即可:

current_path: Path = Path(__file__).parent.resolve()

t
twasbrillig

“当前在进程中运行的文件的文件路径”是什么意思并不完全清楚。 sys.argv[0] 通常包含 Python 解释器调用的脚本的位置。查看 sys documentation 了解更多详情。

正如@Tim 和@Pat Notz 所指出的, __file__ 属性提供了对

加载模块的文件,如果它是从文件加载的


当我们将 python 程序传递给 win32 exe 时,“print os.path.abspath(file)”和“print inspect.getfile(inspect.currentframe())”不起作用。只有 sys.argv[0] 有效! :) 但你只知道名字!
v
vishal ekhe
import os
print os.path.basename(__file__)

这只会给我们文件名。即如果文件的绝对路径是 c:\abcd\abc.py 那么第二行将打印 abc.py


J
Jahid

我有一个必须在 windows 环境下工作的脚本。这段代码是我完成的:

import os,sys
PROJECT_PATH = os.path.abspath(os.path.split(sys.argv[0])[0])

这是一个很老套的决定。但它不需要外部库,这对我来说是最重要的。


为此,我必须“导入 os,sys”,但到目前为止,这是最好的答案,它实际上只返回字符串末尾没有文件名的路径。
S
Soumyajit

尝试这个,

import os
os.path.dirname(os.path.realpath(__file__))

G
Gergo Erdosi
import os
os.path.dirname(os.path.abspath(__file__))

无需检查或任何其他库。

当我必须导入一个脚本(从不同的目录然后是执行的脚本)时,这对我有用,该脚本使用与导入脚本位于同一文件夹中的配置文件。


如果当前工作目录 (os.getcwd) 与文件所在的目录不同,这将不会产生所需的答案。
怎么会这样?在这种情况下对我来说很好。我得到文件所在的目录。
@IronPillow 也许这个答案会帮助你满足你的需要。 stackoverflow.com/a/41546830/3123191
B
Brian Burns

__file__ 属性适用于包含主要执行代码的文件以及导入的模块。

请参阅https://web.archive.org/web/20090918095828/http://pyref.infogami.com/__file__


a
appusajeev
import sys

print sys.path[0]

这将打印当前执行脚本的路径


sys.path[0] 很有用,但是给出了 script1 的路径,而不是按要求给出了 script3
至少在 2.7 的 OS X 上,我觉得这没有什么可靠的。如果直接执行相同的文件,它会起作用。不适用于 repl,尤其是进口鸡蛋
s
smparkes

我认为这只是 __file__ 听起来您可能还想查看 inspect module


啊... execfile 很棘手。请参阅我关于使用检查模块的另一篇文章。
J
Jahid

您可以使用 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'

W
WBAR
import sys
print sys.argv[0]

不幸的是,这仅在使用完整路径调用脚本时才有效,因为它仅在命令行上返回“第一个参数”,即对脚本的调用。
B
BaiJiFeiLong
print(__file__)
print(__import__("pathlib").Path(__file__).parent)

不鼓励仅使用代码的答案。请添加一些解释,说明这如何解决问题,或者这与现有答案有何不同。 From Review
J
Jahid

这应该有效:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))

T
Tiago Martins Peres

这是我使用的,所以我可以毫无问题地将我的代码扔到任何地方。 __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__))

p
pbaranski

获取执行脚本的目录

 print os.path.dirname( inspect.getfile(inspect.currentframe()))

m
mik80

我使用 __file__
os.path.abspath(__file__)
的方法,但有一个小技巧,它在第一次运行代码时返回 .py 文件,下一次运行给出 *.pyc 文件的名称
所以我留在了:
inspect.getfile(inspect.currentframe())

sys._getframe().f_code.co_filename


h
hayj

我写了一个考虑到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_))

L
Lucas Azevedo

最简单的方法是:

在 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>


n
nichoio

以下返回当前主脚本所在的路径。我用 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]))