获取当前脚本的名称Python
我想获取当前正在运行的Python脚本的名字。
我有一个叫做 foo.py
的脚本,我想用类似下面的方式来获取这个脚本的名字:
print(Scriptname)
14 个回答
为了让大家更清楚,我觉得有必要总结一下可能的结果,并提供每种情况的具体行为参考。
这个回答分为四个部分:
列出几种方法,可以获取当前正在执行的脚本的完整路径。
关于相对路径处理的注意事项。
关于符号链接处理的建议。
介绍几种方法,可以从完整路径中提取实际的文件名,包括文件后缀或不包括文件后缀。
提取完整文件路径
__file__
是当前正在执行的文件,具体内容可以参考官方文档:__file__
是模块加载的文件路径,如果是从文件加载的模块。对于某些类型的模块,比如静态链接到解释器的C模块,可能没有__file__
属性;而对于从共享库动态加载的扩展模块,它就是共享库文件的路径。从Python3.4 开始,根据18416号问题,
__file__
总是一个绝对路径,除非当前执行的文件是通过相对路径直接执行的脚本(而不是通过解释器使用-m
命令行选项执行的)。__main__.__file__
(需要导入__main__
)简单地访问上述__file__
属性,指的是从命令行调用的脚本的主模块。从Python3.9 开始,根据20443号问题,
__main__
模块的__file__
属性变成了绝对路径,而不是相对路径。sys.argv[0]
(需要导入sys
)是从命令行调用的脚本名称,可能是绝对路径,具体内容可以参考官方文档:argv[0]
是脚本名称(这是否是完整路径取决于操作系统)。如果命令是通过解释器的-c
命令行选项执行的,argv[0]
会被设置为字符串'-c'
。如果没有传递脚本名称给Python解释器,argv[0]
就是空字符串。正如在另一个回答中提到的,通过像py2exe或PyInstaller这样的工具将Python脚本转换为独立可执行程序时,使用这种方法可能无法得到想要的结果(即
sys.argv[0]
会包含可执行文件的名称,而不是该可执行文件内主Python文件的名称)。如果上述选项都不奏效,可能是由于不寻常的执行过程或不规则的导入操作,可以尝试使用inspect模块,正如在另一个回答中提到的:
import inspect source_file_path = inspect.getfile(inspect.currentframe())
不过,inspect.currentframe() 在没有Python堆栈帧的实现中会引发异常。
请注意,inspect.getfile(...) 比inspect.getsourcefile(...)更受欢迎,因为后者在只能确定二进制文件而不是对应源文件时,会引发TypeError异常(另见另一个问题的回答)。
从Python3.6开始,正如在另一个回答中提到的,可以安装一个外部开源库lib_programname,它专门提供这个问题的完整解决方案。
这个库会遍历上述所有方法,直到返回一个有效的路径。如果所有方法都失败,它会引发异常。它还尝试解决各种陷阱,比如通过pytest框架或pydoc模块的调用。
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.chdir(...)
改变当前工作目录,然后再调用这些方法,它们就会返回错误的路径。
处理符号链接
如果当前脚本是一个符号链接,那么上述所有方法都会返回符号链接的路径,而不是实际文件的路径,这时应该调用os.path.realpath(...)
来提取实际文件的路径。
进一步提取实际文件名的方法
可以在上述任意方法上调用os.path.basename(...)
来提取实际文件名,并且可以在实际文件名上调用os.path.splitext(...)
来去掉文件后缀,比如使用os.path.splitext(os.path.basename(...))
。
从Python 3.4开始,根据PEP 428,可以使用PurePath
类,作为上述方法的替代。具体来说,pathlib.PurePath(...).name
可以提取实际文件名,而pathlib.PurePath(...).stem
可以提取不带后缀的实际文件名。
import sys
print(sys.argv[0])
这段话的意思是,当你输入 python foo.py
时,它会显示 foo.py
,而输入 python dir/foo.py
时,它会显示 dir/foo.py
,等等。这里提到的就是你给 python
的第一个参数。(注意,如果你用的是 py2exe,那么它会变成 foo.exe
。)
你可以使用 __file__
来获取当前文件的名字。当在主模块中使用时,这个名字就是最开始运行的脚本的名字。
如果你想去掉文件路径中的目录部分(可能会有),可以使用 os.path.basename(__file__)
。