这似乎是一个新手问题,但事实并非如此。一些常见的方法并不适用于所有情况:
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
首先,您需要从 inspect
和 os
导入
from inspect import getsourcefile
from os.path import abspath
接下来,无论您想从哪里找到源文件,只需使用
abspath(getsourcefile(lambda: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))
一些路径/main.py:
import module_locator
my_path = module_locator.module_path()
如果您在不同目录中有多个主脚本,则可能需要多个 module_locator 副本。
当然,如果您的主脚本是由其他一些工具加载的,而这些工具不允许您导入与您的脚本位于同一位置的模块,那么您就不走运了。在这种情况下,您所追求的信息根本不存在于您的程序中的任何地方。您最好的选择是向该工具的作者提交错误。
NameError: global name '__file__' is not defined
,这不在 IDLE 内。认为 __file__
仅在模块内部定义。
__file__
的问题与 Unicode 无关。我不知道为什么没有定义 __file__
,但我正在寻找一个通用的解决方案,这将适用于所有情况。
some_path/module_locator.py
的位置吗?
即使在可执行文件中,此解决方案也很强大:
import inspect, os.path
filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
entry_point: console_script
,但没有其他答案。
cwd()
中
我遇到了类似的问题,我认为这可能会解决问题:
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_。
module_path()
的调用中定义本地函数。即 module_path(lambda _: None)
它不依赖于它所在的脚本的其他内容。
lambda _: None
的建议,并且在过去的两年中一直在使用它,但现在我发现我可以将其浓缩为 lambda:0
。您是否有任何特殊原因建议您使用 _
的忽略参数而不是根本没有参数?以空格为前缀的 None
而不仅仅是 0
有什么更好的地方吗?我认为它们都同样神秘,只有一个长 8 个字符,而另一个长 14 个字符。
lambda _:
是一个接受一个参数的函数,而 lambda:
是一个不接受任何参数的函数。没关系,因为该函数永远不会被调用。同样,使用什么返回值也没有关系。我想我选择了 None
,因为当时它似乎表明它是一个无所事事、永远不会被调用的函数。它前面的空间是可选的,并且只是为了提高可读性(总是试图遵循 PEP8 是习惯形成)。
lambda
的滥用,将它用于从未打算做的事情。如果您要遵循 PEP8,我认为它的正确内容应该是 pass
,而不是 None
,但是在 lambda
中放入语句是无效的,因此您必须放入具有值的内容。您可以输入一些有效的 2 字符内容,但我认为您可以输入的唯一有效的单字符内容是 0-9(或在 lambda
之外分配的单个字符变量名称。)我认为 0
最好表示0-9的虚无。
您只需调用:
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()
返回不带文件名的目录路径。
简短的回答是,没有保证获得所需信息的方法,但是在实践中几乎总是存在启发式方法。您可能会查看 How do I find the location of the executable in C?。它从 C 的角度讨论了这个问题,但是提出的解决方案很容易被转录成 Python。
有关相关信息,请参阅我对问题 Importing modules from parent folder 的回答,包括为什么我的回答不使用不可靠的 __file__
变量。这个简单的解决方案应该与不同的操作系统交叉兼容,因为模块 os
和 inspect
是 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 中返回 '
对 getsourcefile(lambda:0)
的结果使用 abspath
应确保生成的文件路径是 Python 文件的完整文件路径。
此解释的解决方案最初基于 How do I get the path of the current executed file in Python? 答案中的代码。
这应该以跨平台的方式解决问题(只要您不使用解释器或其他东西):
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__
)。
请注意,如果您的脚本是符号链接,它将为您提供它链接到的文件的路径(而不是符号链接的路径)。
您可以使用 pathlib
模块中的 Path
:
from pathlib import Path
# ...
Path(__file__)
您可以使用对 parent
的调用在路径中走得更远:
Path(__file__).parent
__file__
变量(并不总是完整的文件路径,不适用于每个操作系统等)。将答案更改为不包括它将导致更少的问题并且更具交叉兼容性。有关详细信息,请参阅 stackoverflow.com/a/33532002/3787376。
只需添加以下内容:
from sys import *
path_to_current_file = sys.argv[0]
print(path_to_current_file)
或者:
from sys import *
print(sys.argv[0])
如果代码来自文件,您可以获得其全名
sys._getframe().f_code.co_filename
您还可以将函数名称检索为 f_code.co_name
主要思想是,有人会运行你的 python 代码,但你需要获取离 python 文件最近的文件夹。
我的解决方案是:
import os
print(os.path.dirname(os.path.abspath(__file__)))
使用 os.path.dirname(os.path.abspath(__file__))
您可以使用它来保存照片、输出文件等
import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))
'__file__'
不应该是字符串,其次,如果你做了__file__
,这将只适用于这行代码所在的文件,而不是执行的文件?
NameError: global name '__file__' is not defined
之类的问题(另一个解决方案导致了这种情况)。lambda:_
。它对我有用 - 不确定它是否会一直有效。lambda:0
可能运行得更快一些(或者可能不是那么小......对于0
来说可能是立即加载或者甚至更快,而对于_
来说是全局加载?)是否更清洁或更容易阅读或更聪明/晦涩难懂。getsourcefile(lambda:0)
将毫无意义,如果您尝试在交互式提示符下运行它只会返回None
(因为lambda
不会在任何源文件。)如果您想知道交互式环境中另一个函数或对象的来源,也许abspath(getsourcefile(thatFunctionOrObject))
对您更有帮助?