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

问题:如何在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__属性,但是有一种解决方法
  • 当您从IDLE运行时,execute()没有__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

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

This may seem like a newbie question, but it is not. Some common approaches don’t work in all cases:

sys.argv[0]

This means using path = os.path.abspath(os.path.dirname(sys.argv[0])), but this does not work if you are running from another Python script in another directory, and this can happen in real life.

__file__

This means using path = os.path.abspath(os.path.dirname(__file__)), but I found that this doesn’t work:

  • py2exe doesn’t have a __file__ attribute, but there is a workaround
  • When you run from IDLE with execute() there is no __file__ attribute
  • OS X 10.6 where I get NameError: global name '__file__' is not defined

Related questions with incomplete answers:

I’m looking for a generic solution, one that would work in all above use cases.

Update

Here is the result of a testcase:

Output of python a.py (on 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

tree

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

回答 0

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

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

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

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

You can’t directly determine the location of the main script being executed. After all, sometimes the script didn’t come from a file at all. For example, it could come from the interactive interpreter or dynamically generated code stored only in memory.

However, you can reliably determine the location of a module, since modules are always loaded from a file. If you create a module with the following code and put it in the same directory as your main script, then the main script can import the module and use that to locate itself.

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

If you have several main scripts in different directories, you may need more than one copy of module_locator.

Of course, if your main script is loaded by some other tool that doesn’t let you import modules that are co-located with your script, then you’re out of luck. In cases like that, the information you’re after simply doesn’t exist anywhere in your program. Your best bet would be to file a bug with the authors of the tool.


回答 1

首先,您需要从inspect和导入os

from inspect import getsourcefile
from os.path import abspath

接下来,只要您要在哪里使用它就可以找到源文件

abspath(getsourcefile(lambda:0))

First, you need to import from inspect and os

from inspect import getsourcefile
from os.path import abspath

Next, wherever you want to find the source file from you just use

abspath(getsourcefile(lambda:0))

回答 2

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

import inspect, os.path

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

this solution is robust even in executables

import inspect, os.path

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

回答 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://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__。

I was running into a similar problem, and I think this might solve the problem:

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

It works for regular scripts and in idle. All I can say is try it out for others!

My typical usage:

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

global __modpath__
__modpath__ = module_path(main)

Now I use __modpath__ instead of __file__.


回答 4

简短的答案是,无法保证获得所需信息的方法,但是在实践中,启发式方法几乎总是起作用。您可能会看看如何在C中找到可执行文件的位置?。它从C的角度讨论了该问题,但是提出的解决方案很容易被转录为Python。

The short answer is that there is no guaranteed way to get the information you want, however there are heuristics that work almost always in practice. You might look at How do I find the location of the executable in C?. It discusses the problem from a C point of view, but the proposed solutions are easily transcribed into Python.


回答 5

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

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

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函数对象的内部源文件,因此'<pyshell#nn>'在Python shell中返回或返回当前正在执行的Python代码的文件路径。

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

See my answer to the question Importing modules from parent folder for related information, including why my answer doesn’t use the unreliable __file__ variable. This simple solution should be cross-compatible with different operating systems as the modules os and inspect come as part of Python.

First, you need to import parts of the inspect and os modules.

from inspect import getsourcefile
from os.path import abspath

Next, use the following line anywhere else it’s needed in your Python code:

abspath(getsourcefile(lambda:0))

How it works:

From the built-in module os (description below), the abspath tool is imported.

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

Then getsourcefile (description below) is imported from the built-in module inspect.

Get useful information from live Python objects.

  • abspath(path) returns the absolute/full version of a file path
  • getsourcefile(lambda:0) somehow gets the internal source file of the lambda function object, so returns '<pyshell#nn>' in the Python shell or returns the file path of the Python code currently being executed.

Using abspath on the result of getsourcefile(lambda:0) should make sure that the file path generated is the full file path of the Python file.
This explained solution was originally based on code from the answer at How do I get the path of the current executed file in Python?.


回答 6

您只是简单地打电话给:

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

You have simply called:

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

instead of:

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

abspath() gives you the absolute path of sys.argv[0] (the filename your code is in) and dirname() returns the directory path without the filename.


回答 7

这应该以跨平台的方式来解决问题(只要您不使用解释器之类):

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上不起作用(因为我听说__file__Mac上不存在此解决方案)。

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

This should do the trick in a cross-platform way (so long as you’re not using the interpreter or something):

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] is the directory that your calling script is in (the first place it looks for modules to be used by that script). We can take the name of the file itself off the end of sys.argv[0] (which is what I did with os.path.basename). os.path.join just sticks them together in a cross-platform way. os.path.realpath just makes sure if we get any symbolic links with different names than the script itself that we still get the real name of the script.

I don’t have a Mac; so, I haven’t tested this on one. Please let me know if it works, as it seems it should. I tested this in Linux (Xubuntu) with Python 3.4. Note that many solutions for this problem don’t work on Macs (since I’ve heard that __file__ is not present on Macs).

Note that if your script is a symbolic link, it will give you the path of the file it links to (and not the path of the symbolic link).


回答 8

您可以Pathpathlib模块中使用:

from pathlib import Path

# ...

Path(__file__)

您可以使用call进行parent进一步操作:

Path(__file__).parent

You can use Path from the pathlib module:

from pathlib import Path

# ...

Path(__file__)

You can use call to parent to go further in the path:

Path(__file__).parent

回答 9

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

sys._getframe().f_code.co_filename

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

If the code is coming from a file, you can get its full name

sys._getframe().f_code.co_filename

You can also retrieve the function name as f_code.co_name


回答 10

只需添加以下内容:

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

要么:

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

Simply add the following:

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

Or:

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

回答 11

我的解决方案是:

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

My solution is:

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

回答 12

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