Get name of current script in Python
I'm tr开发者_Go百科ying to get the name of the Python script that is currently running.
I have a script called foo.py
and I'd like to do something like this in order to get the script name:
print(Scriptname)
You can use __file__
to get the name of the current file. When used in the main module, this is the name of the script that was originally invoked.
If you want to omit the directory part (which might be present), you can use os.path.basename(__file__)
.
import sys
print(sys.argv[0])
This will print foo.py
for python foo.py
, dir/foo.py
for python dir/foo.py
, etc. It's the first argument to python
. (Note that after py2exe it would be foo.exe
.)
For completeness' sake, I thought it would be worthwhile summarizing the various possible outcomes and supplying references for the exact behaviour of each.
The answer is composed of four sections:
A list of different approaches that return the full path to the currently executing script.
A caveat regarding handling of relative paths.
A recommendation regarding handling of symbolic links.
An account of a few methods that could be used to extract the actual file name, with or without its suffix, from the full file path.
Extracting the full file path
__file__
is the currently executing file, as detailed in the official documentation:__file__
is the pathname of the file from which the module was loaded, if it was loaded from a file. The__file__
attribute may be missing for certain types of modules, such as C modules that are statically linked into the interpreter; for extension modules loaded dynamically from a shared library, it is the pathname of the shared library file.From Python3.4 onwards, per issue 18416,
__file__
is always an absolute path, unless the currently executing file is a script that has been executed directly (not via the interpreter with the-m
command line option) using a relative path.__main__.__file__
(requires importing__main__
) simply accesses the aforementioned__file__
attribute of the main module, e.g. of the script that was invoked from the command line.From Python3.9 onwards, per issue 20443, the
__file__
attribute of the__main__
module became an absolute path, rather than a relative path.sys.argv[0]
(requires importingsys
) is the script name that was invoked from the command line, and might be an absolute path, as detailed in the official documentation:argv[0]
is the script name (it is operating system dependent whether this is a full pathname or not). If the command was executed using the-c
command line option to the interpreter,argv[0]
is set to the string'-c'
. If no script name was passed to the Python interpreter,argv[0]
is the empty string.As mentioned in another answer to this question, Python scripts that were converted into stand-alone executable programs via tools such as py2exe or PyInstaller might not display the desired result when using this approach (i.e.
sys.argv[0]
would hold the name of the executable rather than the name of the main Python file within that executable).If none of the aforementioned options seem to work, probably due to an atypical execution process or an irregular import operation, the inspect module might prove useful, as suggested in another answer to this question:
import inspect source_file_path = inspect.getfile(inspect.currentframe())
However, inspect.currentframe() would raise an exception when running in an implementation without Python stack frame.
Note that inspect.getfile(...) is preferred over inspect.getsourcefile(...) because the latter raises a TypeError exception when it can determine only a binary file, not the corresponding source file (see also this answer to another question).
From Python3.6 onwards, and as detailed in another answer to this question, it's possible to install an external open source library, lib_programname, which is tailored to provide a complete solution to this problem.
This library iterates through all of the approaches listed above until a valid path is returned. If all of them fail, it raises an exception. It also tries to address various pitfalls, such as invocations via the pytest framework or the pydoc module.
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
Handling relative paths
When dealing with an approach that happens to return a relative path, it might be tempting to invoke various path manipulation functions, such as os.path.abspath(...)
or os.path.realpath(...)
in order to extract the full or real path.
However, these methods rely on the current path in order to derive the full path. Thus, if a program first changes the current working directory, for example via os.chdir(...)
, and only then invokes these methods, they would return an incorrect path.
Handling symbolic links
If the current script is a symbolic link, then all of the above would return the path of the symbolic link rather than the path of the real file and os.path.realpath(...)
should be invoked in order to extract the latter.
Further manipulations that extract the actual file name
os.path.basename(...)
may be invoked on any of the above in order to extract the actual file name and os.path.splitext(...)
may be invoked on the actual file name in order to truncate its suffix, as in os.path.splitext(os.path.basename(...))
.
From Python 3.4 onwards, per PEP 428, the PurePath
class of the pathlib
module may be used as well on any of the above. Specifically, pathlib.PurePath(...).name
extracts the actual file name and pathlib.PurePath(...).stem
extracts the actual file name without its suffix.
Note that __file__
will give the file where this code resides, which can be imported and different from the main file being interpreted. To get the main file, the special __main__ module can be used:
import __main__ as main
print(main.__file__)
Note that __main__.__file__
works in Python 2.7 but not in 3.2, so use the import-as syntax as above to make it portable.
The Above answers are good . But I found this method more efficient using above results.
This results in actual script file name not a path.
import sys
import os
file_name = os.path.basename(sys.argv[0])
For modern Python versions (3.4+), Path(__file__).name
should be more idiomatic. Also, Path(__file__).stem
gives you the script name without the .py
extension.
Try this:
print __file__
If you're doing an unusual import (e.g., it's an options file), try:
import inspect
print (inspect.getfile(inspect.currentframe()))
Note that this will return the absolute path to the file.
As of Python 3.5 you can simply do:
from pathlib import Path
Path(__file__).stem
See more here: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem
For example, I have a file under my user directory named test.py
with this inside:
from pathlib import Path
print(Path(__file__).stem)
print(__file__)
running this outputs:
>>> python3.6 test.py
test
test.py
You can do this without importing os or other libs.
If you want to get the path of current python script, use: __file__
If you want to get only the filename without .py extension, use this:
__file__.rsplit("/", 1)[1].split('.')[0]
we can try this to get current script name without extension.
import os
script_name = os.path.splitext(os.path.basename(__file__))[0]
Since the OP asked for the name of the current script file I would prefer
import os
os.path.split(sys.argv[0])[1]
all that answers are great, but have some problems You might not see at the first glance.
lets define what we want - we want the name of the script that was executed, not the name of the current module - so __file__
will only work if it is used in the executed script, not in an imported module.
sys.argv
is also questionable - what if your program was called by pytest ? or pydoc runner ? or if it was called by uwsgi ?
and - there is a third method of getting the script name, I havent seen in the answers - You can inspect the stack.
Another problem is, that You (or some other program) can tamper around with sys.argv
and __main__.__file__
- it might be present, it might be not. It might be valid, or not. At least You can check if the script (the desired result) exists !
the library lib_programname does exactly that :
- check if
__main__
is present - check if
__main__.__file__
is present - does give
__main__.__file__
a valid result (does that script exist ?) - if not: check sys.argv:
- is there pytest, docrunner, etc in the sys.argv ? --> if yes, ignore that
- can we get a valid result here ?
- if not: inspect the stack and get the result from there possibly
- if also the stack does not give a valid result, then throw an Exception.
by that way, my solution is working so far with setup.py test
, uwsgi
, pytest
, pycharm pytest
, pycharm docrunner (doctest)
, dreampie
, eclipse
there is also a nice blog article about that problem from Dough Hellman, "Determining the Name of a Process from Python"
BTW, it will change again in python 3.9 : the file attribute of the main module became an absolute path, rather than a relative path. These paths now remain valid after the current directory is changed by os.chdir()
So I rather want to take care of one small module, instead of skimming my codebase if it should be changed somewere ...
Disclaimer: I'm the author of the lib_programname library.
if you get script path in base class, use this code, subclass will get script path correctly.
sys.modules[self.__module__].__file__
精彩评论