How do you properly determine the current script directory in Python?

后端 未结 12 1649
情深已故
情深已故 2020-11-22 02:30

I would like to see what is the best way to determine the current script directory in Python.

I discovered that, due to the many ways of calling Python code, it is ha

相关标签:
12条回答
  • 2020-11-22 02:49

    In Python 3.4+ you can use the simpler pathlib module:

    from inspect import currentframe, getframeinfo
    from pathlib import Path
    
    filename = getframeinfo(currentframe()).filename
    parent = Path(filename).resolve().parent
    

    You can also use __file__ to avoid the inspect module altogether:

    from pathlib import Path
    parent = Path(__file__).resolve().parent
    
    0 讨论(0)
  • 2020-11-22 02:49

    For .py scripts as well as interactive usage:

    I frequently use the directory of my scripts (for accessing files stored along side them), but I also frequently run these scripts in an interactive shell for debugging purposes. I define __dirpath__ as:

    • When running or importing a .py file, the file's base directory. This is always the correct path.
    • When running an .ipyn notebook, the current working directory. This is always the correct path, since Jupyter sets the working directory as the .ipynb base directory.
    • When running in a REPL, the current working directory. Hmm, what is the actual "correct path" when the code is detached from a file? Rather, make it your responsibility to change into the "correct path" before invoking the REPL.

    Python 3.4 (and above):

    from pathlib import Path
    __dirpath__ = Path(globals().get("__file__", "./_")).absolute().parent
    

    Python 2 (and above):

    import os
    __dirpath__ = os.path.dirname(os.path.abspath(globals().get("__file__", "./_")))
    

    Explanation:

    • globals() returns all the global variables as a dictionary.
    • .get("__file__", "./_") returns the value from the key "__file__" if it exists in globals(), otherwise it returns the provided default value "./_".
    • The rest of the code just expands __file__ (or "./_") into an absolute filepath, and then returns the filepath's base directory.
    0 讨论(0)
  • 2020-11-22 02:50

    Here is a partial solution, still better than all published ones so far.

    import sys, os, os.path, inspect
    
    #os.chdir("..")
    
    if '__file__' not in locals():
        __file__ = inspect.getframeinfo(inspect.currentframe())[0]
    
    print os.path.dirname(os.path.abspath(__file__))
    

    Now this works will all calls but if someone use chdir() to change the current directory, this will also fail.

    Notes:

    • sys.argv[0] is not going to work, will return -c if you execute the script with python -c "execfile('path-tester.py')"
    • I published a complete test at https://gist.github.com/1385555 and you are welcome to improve it.
    0 讨论(0)
  • 2020-11-22 02:57

    If you really want to cover the case that a script is called via execfile(...), you can use the inspect module to deduce the filename (including the path). As far as I am aware, this will work for all cases you listed:

    filename = inspect.getframeinfo(inspect.currentframe()).filename
    path = os.path.dirname(os.path.abspath(filename))
    
    0 讨论(0)
  • 2020-11-22 02:58

    Hopefully this helps:- If you run a script/module from anywhere you'll be able to access the __file__ variable which is a module variable representing the location of the script.

    On the other hand, if you're using the interpreter you don't have access to that variable, where you'll get a name NameError and os.getcwd() will give you the incorrect directory if you're running the file from somewhere else.

    This solution should give you what you're looking for in all cases:

    from inspect import getsourcefile
    from os.path import abspath
    abspath(getsourcefile(lambda:0))
    

    I haven't thoroughly tested it but it solved my problem.

    0 讨论(0)
  • 2020-11-22 03:00
    #!/usr/bin/env python
    import inspect
    import os
    import sys
    
    def get_script_dir(follow_symlinks=True):
        if getattr(sys, 'frozen', False): # py2exe, PyInstaller, cx_Freeze
            path = os.path.abspath(sys.executable)
        else:
            path = inspect.getabsfile(get_script_dir)
        if follow_symlinks:
            path = os.path.realpath(path)
        return os.path.dirname(path)
    
    print(get_script_dir())
    

    It works on CPython, Jython, Pypy. It works if the script is executed using execfile() (sys.argv[0] and __file__ -based solutions would fail here). It works if the script is inside an executable zip file (/an egg). It works if the script is "imported" (PYTHONPATH=/path/to/library.zip python -mscript_to_run) from a zip file; it returns the archive path in this case. It works if the script is compiled into a standalone executable (sys.frozen). It works for symlinks (realpath eliminates symbolic links). It works in an interactive interpreter; it returns the current working directory in this case.

    0 讨论(0)
提交回复
热议问题