ChatGPT解决这个技术问题 Extra ChatGPT

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

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

sys.argv[0]

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

__文件__

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

py2exe 没有 __file__ 属性,但有一个解决方法

当您使用 execute() 从 IDLE 运行时,没有 __file__ 属性

Mac OS X v10.6 (Snow Leopard) 我得到 NameError: global name '__file__' is not defined

答案不完整的相关问题:

查找当前运行文件的路径

当前文件的路径取决于我如何执行程序

如何知道 Python 中运行脚本的路径?

将目录更改为 Python 脚本的目录

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

更新

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

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

一个.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")

文件子目录/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

A
ArtOfWarfare

首先,您需要从 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 (因为 lambda 不会在任何源文件。)如果您想知道交互式环境中另一个函数或对象的来源,也许 abspath(getsourcefile(thatFunctionOrObject)) 对您更有帮助?
D
Daniel Stutzbach

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

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

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

一些路径/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 的位置吗?
P
Peter Mortensen

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

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()
P
Peter Mortensen

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

def module_path(local_function):
   ''' returns the module path without the use of __file__.  Requires a function defined
   locally in the module.
   from http://stackoverflow.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的虚无。
d
dgb

您只需调用:

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() 返回不带文件名的目录路径。


C
Community

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


你好,我的标志被拒绝了,所以我现在开始讨论元:meta.stackoverflow.com/questions/277272/…
但是,此页面上已经有简单的工作答案。我的解决方案效果很好:stackoverflow.com/a/33531619/3787376
E
Edward

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

首先,您需要导入部分检查和操作系统模块。

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 中返回 '' 或返回当前正在执行的 Python 代码的文件路径。

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


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

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

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

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


G
Gavriel Cohen

您可以使用 pathlib 模块中的 Path

from pathlib import Path

# ...

Path(__file__)

您可以使用对 parent 的调用在路径中走得更远:

Path(__file__).parent

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

只需添加以下内容:

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

或者:

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

A
Alex Cohn

如果代码来自文件,您可以获得其全名

sys._getframe().f_code.co_filename

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


T
ThienSuBS

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

我的解决方案是:

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

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


一个解释将是有序的。例如,想法/要点是什么?请通过 editing (changing) your answer 回复,而不是在评论中(没有“编辑:”、“更新:”或类似内容 - 答案应该看起来好像是今天写的)。
M
Mohamed.Abdo
import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))

这根本不符合逻辑。首先,'__file__'不应该是字符串,其次,如果你做了__file__,这将只适用于这行代码所在的文件,而不是执行的文件?
一个解释将是有序的。例如,想法/要点是什么?请通过 editing (changing) your answer 回复,而不是在评论中(没有“编辑:”、“更新:”或类似内容 - 答案应该看起来好像是今天写的)。