如何获得Python中当前执行文件的path?

这可能看起来像一个新手问题,但事实并非如此。 一些常用的方法在所有情况下都不起作用:

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__属性
  • OS X 10.6我得到的NameError: global name '__file__' is not defined

有不完整答案的相关问题:

  • Python – 查找正在运行的文件的path
  • 当前文件的path取决于我如何执行程序
  • 如何知道在Python中运行脚本的path?
  • 将目录切换到Python脚本的目录

我在寻找一个通用的解决scheme ,一个可以在所有上面的用例中工作的解决scheme

更新

这是一个testing用例的结果:

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

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

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

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

SOME_PATH / module_locator.py:

 def we_are_frozen(): # All of the modules are built-in to the interpreter, eg, 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的多个副本。

当然,如果您的主脚本是由其他工具加载的,而这些工具不允许导入与脚本位于同一位置的模块,那么您运气不好。 在这种情况下,您所查询的信息根本不存在于程序中的任何地方。 你最好的select是向工具的作者提交一个bug。

首先,你需要从inspectos导入

 from inspect import getsourcefile from os.path import abspath 

接下来,无论你想从你find源文件只是使用

 abspath(getsourcefile(lambda:0)) 

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

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

它适用于普通脚本和闲置。 我所能说的只是为别人尝试

我的典型用法:

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

现在我使用__modpath__而不是__file__。

简单的答案是, 没有保证的方式来获得你想要的信息 ,但有启发式,几乎总是在实践中。 你可能会看看如何find可执行文件在C中的位置? 。 它从C的angular度讨论了这个问题,但是提出的解决scheme很容易被转换成Python。

您可以使用pathlib模块中的Path

 from pathlib import Path # ... Path(__file__) 

您可以使用呼叫parent进一步path:

 Path(__file__).parent 

查看我的问题的答案从父文件夹导入模块的相关信息,包括为什么我的答案不使用不可靠的__file__variables。 这个简单的解决scheme应该与不同的操作系统交叉兼容,因为模块osinspect是Python的一部分。

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

 from inspect import getsourcefile from os.path import abspath 

接下来,在Python代码中需要的地方使用下面的代码行:

 abspath(getsourcefile(lambda:0)) 

怎么运行的:

从内置模块os (下面的描述)中, abspath工具被导入。

Mac,NT或Posix的OS例程取决于我们所在的系统。

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

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

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

getsourcefile(lambda:0)的结果使用abspath应确保生成的文件path是Python文件的完整文件path。
这个解释的解决scheme最初是基于来自答案的代码如何在Python中获取当前执行文件的path? 。

这应该以跨平台的方式来做(只要你不使用解释器或其他东西):

 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; 所以,我没有在一个testing。 请让我知道它是否有效,因为它似乎应该。 我用Python 3.4在Linux(Xubuntu)中testing了这个。 请注意,这个问题的许多解决scheme不适用于Mac(因为我听说__file__不存在于Mac上)。

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

该解决scheme即使在可执行文件中也是健壮的

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