如何在 Python 中获取当前执行文件的路径?

Posted

技术标签:

【中文标题】如何在 Python 中获取当前执行文件的路径?【英文标题】:How do I get the path of the current executed file in Python? 【发布时间】:2011-02-07 14:23:43 【问题描述】:

这似乎是一个新手问题,但事实并非如此。一些常见的方法并不适用于所有情况:

sys.argv[0]

这意味着使用path = os.path.abspath(os.path.dirname(sys.argv[0])),但如果您从另一个目录中的另一个 Python 脚本运行,这将不起作用,这可能会发生在现实生活中。

__file__

这意味着使用path = os.path.abspath(os.path.dirname(__file__)),但我发现这不起作用:

py2exe 没有 __file__ 属性,但有 a workaround 当您从 IDLE 和 execute() 运行时,没有 __file__ 属性 Mac OS X v10.6(雪豹)我得到NameError: global name '__file__' is not defined

答案不完整的相关问题:

Find path to currently running file Path to current file depends on how I execute the program How can I know the path of the running script in Python? Change directory to the directory of a Python script

我正在寻找一种通用解决方案,它适用于上述所有用例。

更新

这是一个测试用例的结果:

python a.py 的输出(在 Windows 上)

a.py: __file__= a.py
a.py: os.getcwd()= C:\zzz

b.py: sys.argv[0]= a.py
b.py: __file__= a.py
b.py: os.getcwd()= C:\zzz

a.py

#! /usr/bin/env python
import os, sys

print "a.py: sys.argv[0]=", sys.argv[0]
print "a.py: __file__=", __file__
print "a.py: os.getcwd()=", os.getcwd()
print

execfile("subdir/b.py")

文件subdir/b.py

#! /usr/bin/env python
import os, sys

print "b.py: sys.argv[0]=", sys.argv[0]
print "b.py: __file__=", __file__
print "b.py: os.getcwd()=", os.getcwd()
print

C:.
|   a.py
\---subdir
        b.py

【问题讨论】:

【参考方案1】:

您无法直接确定正在执行的主脚本的位置。毕竟,有时脚本根本不是来自文件。例如,它可能来自交互式解释器或仅存储在内存中的动态生成的代码。

但是,您可以可靠地确定模块的位置,因为模块总是从文件中加载。如果您使用以下代码创建一个模块并将其放在与主脚本相同的目录中,则主脚本可以导入该模块并使用它来定位自己。

some_path/module_locator.py:

def we_are_frozen():
    # All of the modules are built-in to the interpreter, e.g., by py2exe
    return hasattr(sys, "frozen")

def module_path():
    encoding = sys.getfilesystemencoding()
    if we_are_frozen():
        return os.path.dirname(unicode(sys.executable, encoding))
    return os.path.dirname(unicode(__file__, encoding))

some_path/main.py:

import module_locator
my_path = module_locator.module_path()

如果您在不同目录中有多个主脚本,则可能需要多个 module_locator 副本。

当然,如果您的主脚本是由其他一些工具加载的,而这些工具不允许您导入与您的脚本位于同一位置的模块,那么您就不走运了。在这种情况下,您所追求的信息根本不存在于您的程序中的任何地方。最好的办法是向该工具的作者提交错误。

【讨论】:

我提到在 OS 10.6 上我使用 file 得到NameError: global name '__file__' is not defined,这不在 IDLE 中。认为__file__ 仅在模块内部定义。 @Sorin Sbarnea:我用我如何解决这个问题更新了我的答案。 谢谢,但实际上缺少__file__ 的问题与Unicode 无关。我不知道为什么 __file__ 没有定义,但我正在寻找一个通用的解决方案,这将适用于所有情况。 抱歉,这并非在所有情况下都是可能的。例如,我尝试从 wscript 文件 (python) 中的 waf.googlecode.com 中执行此操作。这些文件已执行,但它们不是模块,您不能将它们设为模块(它们可以是源树中的任何子目录)。 这不是给你some_path/module_locator.py的位置吗?【参考方案2】:

简短的回答是无法保证获得您想要的信息,但是在实践中几乎总是有启发式方法。你可以看看How do I find the location of the executable in C?。它从 C 的角度讨论了这个问题,但提出的解决方案很容易被转录成 Python。

【讨论】:

你好,我的标志被拒绝了,所以我现在开始讨论元:meta.***.com/questions/277272/… 然而,此页面上已有简单的工作答案。我的解决方案效果很好:***.com/a/33531619/3787376.【参考方案3】:

我遇到了类似的问题,我认为这可能会解决问题:

def module_path(local_function):
   ''' returns the module path without the use of __file__.  Requires a function defined
   locally in the module.
   from http://***.com/questions/729583/getting-file-path-of-imported-module'''
   return os.path.abspath(inspect.getsourcefile(local_function))

它适用于常规脚本和IDLE。我只能说给别人试试!

我的典型用法:

from toolbox import module_path
def main():
   pass # Do stuff

global __modpath__
__modpath__ = module_path(main)

现在我使用 _modpath_ 而不是 _file_

【讨论】:

根据PEP8 编码风格指南,永远不应该创建带有双前导和尾随下划线的名称——所以__modpath__ 应该被重命名。您也可能不需要global 语句。否则 +1! 其实你可以在module_path()的调用中定义本地函数。即module_path(lambda _: None),它不依赖于它所在脚本的其他内容。 @martineau:我接受了您对lambda _: None 的建议,并且在过去的两年中一直在使用它,但现在我发现我可以将其浓缩为lambda:0。您是否有任何特殊原因建议您使用 _ 忽略的参数,而不是根本没有参数? None 以空格为前缀而不只是 0 有什么更好的地方吗?我认为它们都同样神秘,只有一个长 8 个字符,而另一个长 14 个字符。 @ArtOfWarfare:两者的区别在于lambda _: 是一个接受一个参数的函数,而lambda: 是一个不接受任何参数的函数。没关系,因为该函数永远不会被调用。同样,使用什么返回值也没有关系。我想我选择了None,因为当时它似乎表明它是一个无所事事,永远不会被称为更好的功能。它前面的空间是可选的,而且只是为了提高可读性(总是尝试遵循 PEP8 是养成习惯)。 @martineau:这显然是对lambda 的滥用,将它用于从未打算做的事情。如果你要关注 PEP8,我认为它的正确内容应该是 pass,而不是 None,但在 lambda 中放置声明是无效的,因此你必须放入具有价值的东西。您可以输入一些有效的 2 字符内容,但我认为您可以输入的唯一有效的单字符内容是 0-9(或在 lambda 之外分配的单个字符变量名。)我认为 0 最好表示0-9的虚无。【参考方案4】:

首先,您需要从inspectos 导入

from inspect import getsourcefile
from os.path import abspath

接下来,无论您想从哪里找到源文件,只需使用

abspath(getsourcefile(lambda:0))

【讨论】:

最佳答案。谢谢。 很好的答案。谢谢。它似乎也是最短且最便携(在不同操作系统上运行)的答案,并且不会遇到诸如NameError: global name '__file__' is not defined 之类的问题(另一种解决方案导致了此问题)。 另一种同样简短的可能性:lambda:_。它对我有用 - 不确定它是否会一直有效。 lambda:0 可能运行得更快一些(或者可能不是那么小......对于0 而言可能是立即加载或更快,而对于_ 是全局加载?)是否更清洁或更容易阅读甚至更聪明/晦涩。 与我尝试过的几乎所有提案一样,这只是为我返回 cwd,而不是我正在运行的目录文件(调试)。 @James - 此代码在您正在运行的文件中...运行 getsourcefile(lambda:0) 将毫无意义,如果您尝试在交互式提示符下运行它只会返回 None(因为 @ 987654332@ 不会出现在任何源文件中。)如果您想知道交互式环境中另一个函数或对象的来源,也许abspath(getsourcefile(thatFunctionOrObject)) 对您更有帮助?【参考方案5】:

这应该以跨平台的方式解决问题(只要您不使用解释器或其他东西):

import os, sys
non_symbolic=os.path.realpath(sys.argv[0])
program_filepath=os.path.join(sys.path[0], os.path.basename(non_symbolic))

sys.path[0] 是您的调用脚本所在的目录(它首先查找该脚本要使用的模块)。我们可以从sys.argv[0] 的末尾删除文件本身的名称(这就是我对os.path.basename 所做的)。 os.path.join 只是以跨平台的方式将它们粘在一起。 os.path.realpath 只是确保如果我们得到任何名称与脚本本身不同的符号链接,我们仍然可以获得脚本的真实名称。

我没有 Mac;所以,我还没有测试过这个。请让我知道它是否有效,因为它似乎应该。我使用 Python 3.4 在 Linux (Xubuntu) 中对此进行了测试。请注意,此问题的许多解决方案不适用于 Mac(因为我听说 __file__ 在 Mac 上不存在)。

请注意,如果您的脚本是符号链接,它将为您提供它链接到的文件的路径(而不是符号链接的路径)。

【讨论】:

【参考方案6】:

有关相关信息,请参阅我对问题Importing modules from parent folder 的回答,包括为什么我的回答不使用不可靠的__file__ 变量。这个简单的解决方案应该与不同的操作系统交叉兼容,因为模块 osinspect 是 Python 的一部分。

首先,您需要导入部分 inspectos 模块。

from inspect import getsourcefile
from os.path import abspath

接下来,在 Python 代码中其他任何需要的地方使用以下行:

abspath(getsourcefile(lambda:0))

工作原理:

从内置模块os(下文描述)中,导入了abspath 工具。

适用于 Mac、NT 或 Posix 的操作系统例程,具体取决于我们使用的系统。

然后从内置模块inspect 导入getsourcefile(如下描述)。

从实时 Python 对象中获取有用信息。

abspath(path) 返回文件路径的绝对/完整版本 getsourcefile(lambda:0) 以某种方式获取 lambda 函数对象的内部源文件,因此在 Python shell 中返回 '<pyshell#nn>' 或返回当前正在执行的 Python 代码的文件路径。

getsourcefile(lambda:0)的结果上使用abspath应该确保生成的文件路径是Python文件的完整文件路径。 这个解释的解决方案最初是基于How do I get the path of the current executed file in Python?答案中的代码。

【讨论】:

是的,我只是想出了相同的解决方案...比只是说它不能可靠地完成的答案要好得多...除非问题不是问我认为它是什么...【参考方案7】:

您可以使用pathlib 模块中的Path

from pathlib import Path

# ...

Path(__file__)

您可以调用parent 走得更远:

Path(__file__).parent

【讨论】:

这个答案使用 __file__ 变量,它可能是不可靠(并不总是完整的文件路径,不适用于每个操作系统等)作为 ***用户经常提到。将答案更改为不包含它将导致更少的问题并且更具交叉兼容性。有关详细信息,请参阅***.com/a/33532002/3787376。 @mrroot5 好的,请删除您的评论。【参考方案8】:

即使在可执行文件中,此解决方案也很强大:

import inspect, os.path

filename = inspect.getframeinfo(inspect.currentframe()).filename
path     = os.path.dirname(os.path.abspath(filename))

【讨论】:

这应该是正确的答案。这甚至适用于entry_point: console_script,但没有其他答案。 刚刚得到 cwd() @eric:点存在? @PeterMortensen 正在运行的文件通常不在cwd()【参考方案9】:

只需添加以下内容:

from sys import *
path_to_current_file = sys.argv[0]
print(path_to_current_file)

或者:

from sys import *
print(sys.argv[0])

【讨论】:

【参考方案10】:

你只是简单地调用了:

path = os.path.abspath(os.path.dirname(sys.argv[0]))

代替:

path = os.path.dirname(os.path.abspath(sys.argv[0]))

abspath() 为您提供sys.argv[0] 的绝对路径(代码所在的文件名),dirname() 返回不带文件名的目录路径。

【讨论】:

【参考方案11】:

如果代码来自一个文件,你可以得到它的全名

sys._getframe().f_code.co_filename

您也可以将函数名称检索为f_code.co_name

【讨论】:

【参考方案12】:

主要思想是,有人会运行你的python代码,但你需要找到离python文件最近的文件夹。

我的解决办法是:

import os
print(os.path.dirname(os.path.abspath(__file__)))

os.path.dirname(os.path.abspath(__file__)) 您可以使用它来保存照片、输出文件等。

【讨论】:

解释一下。例如,想法/要点是什么?请通过editing (changing) your answer 回复,而不是在 cmets 中(without "Edit:"、"Update:" 或类似的 - 答案应该看起来像是今天写的)。【参考方案13】:
import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))

【讨论】:

这没有意义。第一,'__file__'不应该是字符串,第二,如果你做了__file__,这只对这行代码所在的文件有效,对执行的文件无效? 解释一下。例如,想法/要点是什么?请通过editing (changing) your answer 回复,而不是在 cmets 中(without "Edit:"、"Update:" 或类似的 - 答案应该看起来像是今天写的)。

以上是关于如何在 Python 中获取当前执行文件的路径?的主要内容,如果未能解决你的问题,请参考以下文章

python3找到当前文件执行路径,并加入临时环境变量

如何获得当前Java文件的路径

pyenv下python依赖的路径和打包项目

如何获取调用 python 可执行文件的路径 [重复]

python 获取文件夹路径问题

python文件执行路径问题