Relative paths in Python

前端 未结 15 1486
陌清茗
陌清茗 2020-11-22 07:39

I\'m building a simple helper script for work that will copy a couple of template files in our code base to the current directory. I don\'t, however, have the absolute path

相关标签:
15条回答
  • 2020-11-22 08:04

    I think to work with all systems use "ntpath" instead of "os.path". Today, it works well with Windows, Linux and Mac OSX.

    import ntpath
    import os
    dirname = ntpath.dirname(__file__)
    filename = os.path.join(dirname, 'relative/path/to/file/you/want')
    
    0 讨论(0)
  • 2020-11-22 08:09

    Hi first of all you should understand functions os.path.abspath(path) and os.path.relpath(path)

    In short os.path.abspath(path) makes a relative path to absolute path. And if the path provided is itself a absolute path then the function returns the same path.

    similarly os.path.relpath(path) makes a absolute path to relative path. And if the path provided is itself a relative path then the function returns the same path.

    Below example can let you understand the above concept properly:

    suppose i have a file input_file_list.txt which contains list of input files to be processed by my python script.

    D:\conc\input1.dic

    D:\conc\input2.dic

    D:\Copyioconc\input_file_list.txt

    If you see above folder structure, input_file_list.txt is present in Copyofconc folder and the files to be processed by the python script are present in conc folder

    But the content of the file input_file_list.txt is as shown below:

    ..\conc\input1.dic

    ..\conc\input2.dic

    And my python script is present in D: drive.

    And the relative path provided in the input_file_list.txt file are relative to the path of input_file_list.txt file.

    So when python script shall executed the current working directory (use os.getcwd() to get the path)

    As my relative path is relative to input_file_list.txt, that is "D:\Copyofconc", i have to change the current working directory to "D:\Copyofconc".

    So i have to use os.chdir('D:\Copyofconc'), so the current working directory shall be "D:\Copyofconc".

    Now to get the files input1.dic and input2.dic, i will read the lines "..\conc\input1.dic" then shall use the command

    input1_path= os.path.abspath('..\conc\input1.dic') (to change relative path to absolute path. Here as current working directory is "D:\Copyofconc", the file ".\conc\input1.dic" shall be accessed relative to "D:\Copyofconc")

    so input1_path shall be "D:\conc\input1.dic"

    0 讨论(0)
  • 2020-11-22 08:11

    This code will return the absolute path to the main script.

    import os
    def whereAmI():
        return os.path.dirname(os.path.realpath(__import__("__main__").__file__))
    

    This will work even in a module.

    0 讨论(0)
  • 2020-11-22 08:13

    summary of the most important commands

    >>> import os
    >>> os.path.join('/home/user/tmp', 'subfolder')
    '/home/user/tmp/subfolder'
    >>> os.path.normpath('/home/user/tmp/../test/..')
    '/home/user'
    >>> os.path.relpath('/home/user/tmp', '/home/user')
    'tmp'
    >>> os.path.isabs('/home/user/tmp')
    True
    >>> os.path.isabs('/tmp')
    True
    >>> os.path.isabs('tmp')
    False
    >>> os.path.isabs('./../tmp')
    False
    >>> os.path.realpath('/home/user/tmp/../test/..') # follows symbolic links
    '/home/user'
    

    A detailed description is found in the docs. These are linux paths. Windows should work analogous.

    0 讨论(0)
  • 2020-11-22 08:13

    From what suggest others and from pathlib documentation, a simple and clear solution is the following (suppose the file we need to refer to: Test/data/users.csv:

    # This file location: Tests/src/long/module/subdir/some_script.py
    from pathlib import Path
    
    # back to Tests/
    PROJECT_ROOT = Path(__file__).parents[4]
    # then down to Test/data/users.csv
    CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'  
    
    with CSV_USERS_PATH.open() as users:
        print(users.read())
    

    Now this looks a bit odd to me, because if you move some_script.py around, the path to the root of our project may change (we would need to modify parents[4]). On the other hand I found a solution that I prefer based on the same idea.

    Suppose we have the following directory structure:

    Tests
    ├── data
    │  └── users.csv
    └── src
       ├── long
       │  └── module
       │     └── subdir
       │        └── some_script.py
       ├── main.py
       └── paths.py
    

    The paths.py file will be responsible for storing the root location of our projet:

    from pathlib import Path
    
    PROJECT_ROOT = Path(__file__).parents[1]
    

    All scripts can now use paths.PROJECT_ROOT to express absolute paths from the root of the project. For example in src/long/module/subdir/some_script.py we could have:

    from paths import PROJECT_ROOT
    
    CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'
    
    def hello():
        with CSV_USERS_PATH.open() as f:
            print(f.read())
    

    And everything goes as expected:

    ~/Tests/src/$ python main.py
    
    /Users/cglacet/Tests/data/users.csv
    hello, user
    
    ~/Tests/$ python src/main.py
    
    /Users/cglacet/Tests/data/users.csv
    hello, user
    

    The main.py script simply is:

    from long.module.subdir import some_script
    
    some_script.hello()
    
    0 讨论(0)
  • 2020-11-22 08:14

    In the file that has the script, you want to do something like this:

    import os
    dirname = os.path.dirname(__file__)
    filename = os.path.join(dirname, 'relative/path/to/file/you/want')
    

    This will give you the absolute path to the file you're looking for. Note that if you're using setuptools, you should probably use its package resources API instead.

    UPDATE: I'm responding to a comment here so I can paste a code sample. :-)

    Am I correct in thinking that __file__ is not always available (e.g. when you run the file directly rather than importing it)?

    I'm assuming you mean the __main__ script when you mention running the file directly. If so, that doesn't appear to be the case on my system (python 2.5.1 on OS X 10.5.7):

    #foo.py
    import os
    print os.getcwd()
    print __file__
    
    #in the interactive interpreter
    >>> import foo
    /Users/jason
    foo.py
    
    #and finally, at the shell:
    ~ % python foo.py
    /Users/jason
    foo.py
    

    However, I do know that there are some quirks with __file__ on C extensions. For example, I can do this on my Mac:

    >>> import collections #note that collections is a C extension in Python 2.5
    >>> collections.__file__
    '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
    dynload/collections.so'
    

    However, this raises an exception on my Windows machine.

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