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

How do I get the path of the current executed file in Python?

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

系统ARVV〔0〕

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

一个文件

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

  • py2exe没有__file__属性,但有一个变通方法
  • 当使用execute()从空闲运行时,没有__file__属性
  • 操作系统x 10.6,在这里我得到了NameError: global name '__file__' is not defined

答案不完整的相关问题:

  • python-查找正在运行的文件的路径
  • 当前文件的路径取决于我如何执行程序
  • 如何知道在python中运行脚本的路径?
  • 将目录更改为python脚本的目录

我正在寻找一个通用的解决方案,它可以在上述所有用例中工作。

更新

以下是测试用例的结果:

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

1
2
3
4
5
6
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

1
2
3
4
5
6
7
8
9
#! /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")

亚DIR/B.Py

1
2
3
4
5
6
7
#! /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

1
2
3
4
C:.
|   a.py
\---subdir
        b.py

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

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

某些路径/模块定位器.py:

1
2
3
4
5
6
7
8
9
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:

1
2
import module_locator
my_path = module_locator.module_path()

如果在不同的目录中有多个主脚本,则可能需要模块定位器的多个副本。

当然,如果您的主脚本是由其他一些不允许您导入与脚本共存的模块的工具加载的,那么您就走运了。在这种情况下,你所需要的信息在你的程序中根本不存在。最好的办法是向工具的作者提交一个bug。


首先,您需要从inspectos进口

1
2
from inspect import getsourcefile
from os.path import abspath

接下来,无论您想从何处查找源文件,只要使用

1
abspath(getsourcefile(lambda:0))


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

1
2
3
4
5
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))

它适用于常规脚本和空闲脚本。我所能说的就是为别人试一试!

我的典型用法:

1
2
3
4
5
6
from toolbox import module_path
def main():
   pass # Do stuff

global __modpath__
__modpath__ = module_path(main)

现在我用modpath代替file。


这个解决方案即使在可执行文件中也很健壮

1
2
3
4
import inspect, os.path

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


简短的回答是,没有保证的方法可以获得您想要的信息,但是,在实践中几乎总是有启发式方法可以工作。您可能会看到我如何在C中找到可执行文件的位置?.它从C的角度讨论了这个问题,但是所提出的解决方案很容易被转换成python。


您只需打电话:

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

而不是:

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

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


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

首先,您需要导入inspect和os模块的部分。

1
2
from inspect import getsourcefile
from os.path import abspath

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

1
abspath(getsourcefile(lambda:0))

它是如何工作的:

从内置模块os中(如下说明)导入abspath工具。

OS routines for Mac, NT, or Posix depending on what system we're on.

然后,从内置模块inspect中导入getsourcefile(如下说明)。

Get useful information from live Python objects.

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

getsourcefile(lambda:0)的结果上使用abspath应确保生成的文件路径是python文件的完整文件路径。这个解释过的解决方案最初是基于答案中的代码,在python中如何获取当前执行文件的路径?.


您可以从pathlib模块使用Path

1
2
3
4
5
from pathlib import Path

# ...

Path(__file__)

您可以使用调用parent在路径中进一步:

1
Path(__file__).parent


这应该以跨平台的方式完成这个技巧(只要您不使用解释器或其他东西):

1
2
3
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)和Python3.4中测试了这个。请注意,这个问题的许多解决方案在Macs上不起作用(因为我听说Macs上没有__file__)。

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


1
2
import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))

我的解决方案是:

1
2
import os
print(os.path.join(os.getcwd(), __file__))


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

1
sys._getframe().f_code.co_filename

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


只需添加以下内容:

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

或:

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