获取Python中当前脚本的名称


407

我正在尝试获取当前正在运行的Python脚本的名称。

我有一个名为的脚本foo.py,我想做这样的事情以获得脚本名称:

print Scriptname

Answers:


620

您可以使用__file__获取当前文件的名称。在主模块中使用时,这是最初调用的脚本的名称。

如果要省略目录部分(可能存在),可以使用os.path.basename(__file__)


15
Python 3.2:“ Exception NameError: NameError("global name '__file__' is not defined",)
sdaau,

20
@sdaau:__file__在交互式解释器中未定义,因为它在那里没有意义。它是由导入实现设置的,因此,如果您使用非标准的导入机制,则可能也未设置它。
斯文·马纳赫

8
至少对于Python 2.7,我认为这import os是必需的。我将此添加到答案中。
Nick Chammas

14
@ cdunn2001:import osimport os.path完全等效。
Sven Marnach 2014年

2
@ sven-marnach:哦,。我做错了很多年了!
cdunn2001

136
import sys
print sys.argv[0]

这将打印foo.pypython foo.pydir/foo.pypython dir/foo.py等,这是第一个参数python。(请注意,在py2exe之后将会是foo.exe。)


33
@DenisMalinovsky:定义“将不起作用”。如果你打电话python linkfile.py,这里linkfile.py是一个符号realfile.pysys.argv[0]将是'linkfile.py',这可能是也可能不是你想要的是; 这当然是我所期望的__file__是一样的:它将是linkfile.py。如果你想找到'realfile.py''linkfile.py',试试os.path.realpath('linkfile.py')
克里斯·摩根

6
+1是因为它(a)更加整洁,并且(b)仍将在模块中工作(其中file变量将是模块文件,而不是已执行的文件)。
罗伯特2015年

这个答案很好,因为它也适用于IDLE。注意,仅获取文件名,您可以编写os.path.basename(sys.argv [0])
Steven Bluen

更重要的是,这仅在主文件内部有效。不要使用此,__file__而是使用。
Apollys支持Monica19

什么!!!你甚至尝试过吗?事实恰恰相反。发问者询问正在运行的python脚本的名称-而不是当前正在执行的python文件。假设您有一个脚本,当发生错误时,该脚本将打印脚本名称以及允许的参数。使用这两种技术之一将其放入函数中。在某个时候,您决定将函数移至外部库。您要打印正在运行的主脚本的名称,还是正在执行的库文件的名称?
John Deighan

70

为了完整起见,我认为值得总结各种可能的结果,并为每种结果的确切行为提供参考:

  • __file__是当前正在执行的文件,如官方文档中所述

    __file__是从中加载模块的文件的路径名(如果它是从文件加载的)。所述__file__属性可以是缺少某些类型的模块,如Ç静态链接到解释器模块; 对于从共享库动态加载的扩展模块,它是共享库文件的路径名。

    从Python3.4起,每发行18416__file__始终是一个绝对路径,除非当前正在执行的文件是已经被直接执行(不通过与解释脚本-m使用相对路径命令行选项)。

  • __main__.__file__(需要import __main__)仅访问主模块的上述__file__属性,例如,从命令行调用的脚本的属性。

  • sys.argv[0](需要import sys)是从命令行调用的脚本名称,并且可能是绝对路径,如官方文档中所述

    argv[0]是脚本名称(是否为完整路径名取决于操作系统)。如果命令是使用-c解释器的命令行选项执行的,argv[0]则将其设置为字符串'-c'。如果没有脚本名称传递给Python解释器,argv[0]则为空字符串。

    正如提到的另一个回答这个问题Python的是被通过的工具,如转换成独立的可执行程序的脚本py2exePyInstaller可能不会显示预期的结果使用这种方法的时候(也就是sys.argv[0]将持有的可执行文件的名称,而不是名称该可执行文件中主要Python文件的名称)。

  • 如果上述选项似乎都不起作用,可能是由于不规则的导入操作造成的,那么检查模块可能会证明是有用的。特别是,在调用inspect.getfile(...)inspect.currentframe()可以工作,尽管后者将返回None没有实现运行时的Python堆栈帧。


处理符号链接

如果当前脚本是符号链接,则以上所有内容都将返回符号链接的路径,而不是真实文件的路径,因此os.path.realpath(...)应调用它们以提取后者。


提取实际文件名的进一步操作

os.path.basename(...)可以在上述任何方法上调用以便提取实际的文件名,os.path.splitext(...)也可以在实际的文件名上调用以便截断其后缀,如中所示os.path.splitext(os.path.basename(...))

Python的3.4起,每PEP 428中,PurePath的的pathlib模块可以用作以及任何上述的。具体来说,pathlib.PurePath(...).name提取实际文件名并pathlib.PurePath(...).stem提取不带后缀的实际文件名。


66

注意 __file__将提供此代码所在的文件,该文件可以导入,并且与要解释的主文件不同。要获取主文件,可以使用特殊的__main__模块:

import __main__ as main
print(main.__file__)

注意 __main__.__file__在Python 2.7中有效,但在3.2中无效,因此请使用上述import-as语法使其具有可移植性。


这在许多情况下都有效,但是当我使用语言rPython包时却无法使用R。那肯定是一个异常情况,很难处理。
狮子座

实际上,rPython软件包嵌入了python解释器,这意味着没有像Python自己运行时那样的“主”文件(在嵌入python的任何时候都会发现相同的行为)。它确实在__main__内部导入,用于在R和之间传递变量python,因此__main__.__file__在调用其他任何东西之前将其设置起来相对容易,但是我什至不确定这种情况下合适的值。
珀金斯

42

上述答案是好的。但是我发现使用上面的结果这种方法更有效。
这导致实际的脚本文件名不是路径。

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])

1
我也喜欢拆分扩展名,所以我使用:os.path.splitext(os.path.basename(sys.argv [0]))[0]
RufusVS



9

注意:如果您使用的是Python 3+,则应改用print()函数

假设文件名为foo.py,则以下代码段

import sys
print sys.argv[0][:-3]

要么

import sys
print sys.argv[0][::-1][3:][::-1]

至于具有更多字符的其他扩展名,例如文件名 foo.pypy

import sys
print sys.argv[0].split('.')[0]

如果要从绝对路径中提取

import sys
print sys.argv[0].split('/')[-1].split('.')[0]

将输出 foo


1
sys.argv [0] [:-3]会做
kon psych

@konpsych更优雅
xtonousou

有差异大__file__sys.argv[0],看到stackoverflow.com/questions/5851588/...
马克西姆Ganenko

8

sys中的第一个参数将是当前文件名,因此它将起作用

   import sys
   print sys.argv[0] # will print the file name

7

如果您执行的是异常导入(例如,这是一个选项文件),请尝试:

import inspect
print (inspect.getfile(inspect.currentframe()))

请注意,这将返回文件的绝对路径。


3

我们可以尝试使用此命令来获取当前脚本名称(不带扩展名)。

import os

script_name = os.path.splitext(os.path.basename(__file__))[0]

2

由于OP要求提供当前脚本文件的名称,所以我希望

import os
os.path.split(sys.argv[0])[1]



0

所有这些答案都很不错,但是有一些问题,您乍一看可能看不到。

让我们定义我们想要的-我们想要执行的脚本的名称,而不是当前模块的名称-因此,__file__只有在已执行的脚本中使用了它,而不是在导入的模块中使用它时,它才起作用。 sys.argv也是可疑的-如果您的程序被pytest调用了怎么办?还是pydocRunner?还是被uwsgi调用?

-还有第三种获取脚本名称的方法,我在答案中没有看到-您可以检查堆栈。

另一个问题是,您(或某些其他程序)可以篡改sys.argv并且__main__.__file__-它可能存在,但可能不存在。它可能有效或无效。至少您可以检查脚本(所需结果)是否存在!

我在github上的库bitranox / lib_programname确实做到了:

  • 检查是否__main__存在
  • 检查是否__main__.__file__存在
  • 确实给 __main__.__file__有效结果(该脚本是否存在?)
  • 如果不是,请检查sys.argv:
  • sys.argv中是否有pytest,docrunner等?->如果是,请忽略
  • 我们可以在这里得到有效的结果吗?
  • 如果不是:检查堆栈并从那里获取结果
  • 如果堆栈也未给出有效结果,则抛出异常。

通过这种方式,我的解决方案正在到目前为止有setup.py testuwsgipytestpycharm pytestpycharm docrunner (doctest)dreampieeclipse

Dough Hellman也有一篇关于该问题的不错的博客文章,“用Python确定进程的名称”。


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里面是这个文件:

from pathlib import Path

print(Path(__file__).stem)
print(__file__)

运行此输出:

>>> python3.6 test.py
test
test.py
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.