我正在尝试获取当前正在运行的Python脚本的名称。
我有一个名为foo.py的脚本,我想做这样的事情,以获得脚本名称:
foo.py
print(Scriptname)
您可以使用__file__来获取当前文件的名称。当在主模块中使用时,这是最初调用的脚本的名称。
__file__
如果希望省略目录部分(可能会出现),可以使用os.path.basename(__file__)。
os.path.basename(__file__)
import sys print(sys.argv[0])
这将为python foo.py打印foo.py,为python dir/foo.py打印dir/foo.py,等等。它是python的第一个参数。(注意,py2exe之后是foo.exe。)
python foo.py
python dir/foo.py
dir/foo.py
python
foo.exe
试试这个:
print __file__
注意,__file__将给出代码所在的文件,该文件可以导入,并且与正在解释的主文件不同。要获得主文件,可以使用特殊的__main__模块:
import __main__ as main print(main.__file__)
请注意,__main__.__file__在Python 2.7中有效,但在3.2中无效,因此使用上面的import-as语法使其可移植。
__main__.__file__
以上答案很好。但是我发现这个方法使用上面的结果更有效 这将导致实际的脚本文件名而不是路径
import sys import os file_name = os.path.basename(sys.argv[0])
为了完整起见,我认为有必要总结各种可能的结果,并为每种结果的确切行为提供参考。
答案由四个部分组成:
返回当前执行脚本完整路径的不同方法的列表。
关于相对路径处理的警告。
关于符号链接处理的建议。
一些方法的说明,这些方法可用于从完整的文件路径中提取实际的文件名(带或不带后缀)。
__file__是当前正在执行的文件,详见官方文档:
__file__是加载模块的文件的路径名,如果它是从一个文件中加载的。对于某些类型的模块,__file__属性可能会丢失,比如静态链接到解释器的C模块;对于从共享库动态加载的扩展模块,它是共享库文件的路径名。
从从< em > Python3.4 < / em >开始,对于发行18416, __file__始终是一个绝对路径,除非当前正在执行的文件是一个使用相对路径直接执行的脚本(而不是通过带有-m命令行选项的解释器)。
-m
__main__.__file__(需要导入__main__)只是访问前面提到的主模块的__file__属性,例如从命令行调用的脚本。
__main__
从从< em > Python3.9 < / em >开始,从发行20443开始,__main__模块的__file__属性变成了一个绝对路径,而不是相对路径。
sys.argv[0](需要导入sys)是从命令行调用的脚本名称,可能是一个绝对路径,详细信息见官方文档:
sys.argv[0]
sys
argv[0]是脚本名(是否为完整路径名取决于操作系统)。如果该命令是使用解释器的-c命令行选项执行的,则argv[0]将被设置为字符串'-c'。如果没有传递脚本名称给Python解释器,则argv[0]为空字符串。
argv[0]
-c
'-c'
正如在这个问题的另一个答案中提到的,通过< em > py2exe < / em >或< em > PyInstaller < / em >等工具转换为独立可执行程序的Python脚本在使用这种方法时可能不会显示所需的结果(即sys.argv[0]将保存可执行文件的名称,而不是该可执行文件中Python主文件的名称)。
import inspect source_file_path = inspect.getfile(inspect.currentframe())
然而,当在没有Python堆栈框架的实现中运行时,inspect.currentframe ()将引发异常。
注意,inspect.getfile(…)优先于inspect.getsourcefile(…),因为后者引发TypeError异常只能确定二进制文件,而不能确定相应的源文件(另请参阅这是另一个问题的答案)。
这个库遍历上面列出的所有方法,直到返回有效路径。如果它们都失败了,就会引发异常。它还尝试解决各种缺陷,例如通过< em > pytest < / em >框架或< em > pydoc < / em >模块进行调用。
import lib_programname # this returns the fully resolved path to the launched python program path_to_program = lib_programname.get_path_executed_script() # type: pathlib.Path
在处理恰好返回相对路径的方法时,可能很容易调用各种路径操作函数,例如os.path.abspath(...)或os.path.realpath(...),以便提取完整或真实的路径。
os.path.abspath(...)
os.path.realpath(...)
但是,这些方法依赖于当前路径来获得完整路径。因此,如果程序首先更改当前工作目录,例如通过os.chdir(...),然后才调用这些方法,则它们将返回错误的路径。
os.chdir(...)
如果当前脚本是一个符号链接,那么上述所有操作都将返回符号链接的路径,而不是实际文件的路径,应该调用os.path.realpath(...)来提取后者。
os.path.basename(...)可以被调用在上面的任何一个上,以提取实际的文件名,os.path.splitext(...)可以被调用在实际的文件名上,以截断它的后缀,如os.path.splitext(os.path.basename(...))。
os.path.basename(...)
os.path.splitext(...)
os.path.splitext(os.path.basename(...))
从Python 3.4 < em > < / em >开始,根据PEP 428, < em > # EYZ1 < / em >模块的< em > # EYZ0 < / em >类也可以用于上述任何一个。具体来说,pathlib.PurePath(...).name提取实际文件名,pathlib.PurePath(...).stem提取不带后缀的实际文件名。
pathlib.PurePath(...).name
pathlib.PurePath(...).stem
如果你正在做一个不寻常的导入(例如,它是一个选项文件),尝试:
import inspect print (inspect.getfile(inspect.currentframe()))
注意,这将返回文件的绝对路径。
对于现代Python版本(3.4+),Path(__file__).name应该更加习惯。此外,Path(__file__).stem提供了脚本名称,但不包含.py扩展名。
Path(__file__).name
Path(__file__).stem
.py
由于OP要求当前脚本文件的名称,我更喜欢
import os os.path.split(sys.argv[0])[1]
我们可以尝试这样做,以获得当前的脚本名称没有扩展名。
import os script_name = os.path.splitext(os.path.basename(__file__))[0]
从Python 3.5开始,你可以简单地做:
from pathlib import Path Path(__file__).stem
更多信息请点击这里:https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem
例如,我在我的用户目录下有一个名为test.py的文件,里面是这样的:
test.py
from pathlib import Path print(Path(__file__).stem) print(__file__)
运行这个输出:
>>> python3.6 test.py test test.py
所有的答案都很棒,但也有一些你第一眼可能看不出来的问题。
让我们定义我们想要的-我们想要执行的脚本的名称,而不是当前模块的名称-所以__file__只在执行的脚本中使用,而不是在导入的模块中使用。 sys.argv也是有问题的——如果你的程序是由pytest调用的呢?还是pydoc runner ?或者它是否被uwsgi调用
sys.argv
还有第三种获取脚本名称的方法,我在答案中没有看到-你可以检查堆栈。
另一个问题是,你(或其他程序)可以篡改sys.argv和__main__.__file__——它可能存在,也可能不存在。它可能成立,也可能不成立。至少您可以检查脚本(期望的结果)是否存在!
lib_programname库正是这样做的:
通过这种方式,我的解决方案是工作到目前为止与setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie, eclipse
setup.py test
uwsgi
pytest
pycharm pytest
pycharm docrunner (doctest)
dreampie
eclipse
Dough Hellman也有一篇关于这个问题的不错的博客文章,“从python中确定进程的名称”;
顺便说一句,它将在python 3.9中再次改变:主要模块的文件属性变成了绝对路径,而不是相对路径。在当前目录被os.chdir()更改后,这些路径仍然有效
所以我宁愿照顾一个小模块,而不是浏览我的代码库,如果它应该改变一些…
免责声明:我是lib_programname库的作者。
你可以在不导入操作系统或其他库的情况下做到这一点。
如果你想获取当前python脚本的路径,请使用:__file__
如果你只想得到没有.py扩展名的文件名,使用这个:
__file__.rsplit("/", 1)[1].split('.')[0]