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

时间:2010-04-13 18:37:46

标签: python path directory

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

sys.argv中[0]

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

__文件__

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

  • py2exe没有__file__属性,但有一个workaround
  • 当您使用execute()从IDLE运行时,没有__file__属性
  • OS X 10.6,我得到NameError: global name '__file__' is not defined

答案不完整的相关问题:

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

更新

以下是测试用例的结果:

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

13 个答案:

答案 0 :(得分:78)

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

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

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副本。

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

答案 1 :(得分:53)

首先,您需要从inspectos

导入
from inspect import getsourcefile
from os.path import abspath

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

即可
abspath(getsourcefile(lambda:0))

答案 2 :(得分:14)

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

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 __。

答案 3 :(得分:9)

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

import inspect, os.path

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

答案 4 :(得分:6)

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

答案 5 :(得分:4)

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

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

from inspect import getsourcefile
from os.path import abspath

接下来,在Python代码中的任何其他位置使用以下行:

abspath(getsourcefile(lambda:0))

工作原理:

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

  

Mac,NT或Posix的OS例程,具体取决于我们所使用的系统。

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

  

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

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

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

答案 6 :(得分:3)

您只需致电:

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

答案 7 :(得分:2)

这应该以跨平台的方式完成(只要你没有使用解释器或其他东西):

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上都不起作用(因为我听说Mac上没有__file__)。

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

答案 8 :(得分:2)

您可以使用Path模块中的pathlib

from pathlib import Path

# ...

Path(__file__)

您可以使用parent的电话进一步走上路径:

Path(__file__).parent

答案 9 :(得分:1)

如果代码来自文件,则可以获取其全名

sys._getframe().f_code.co_filename

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

答案 10 :(得分:0)

只需添加以下内容:

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

或者:

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

答案 11 :(得分:0)

我的解决方法是:

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

答案 12 :(得分:-1)

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