How to retrieve a module's path?

后端 未结 20 1727
无人及你
无人及你 2020-11-22 05:34

I want to detect whether module has changed. Now, using inotify is simple, you just need to know the directory you want to get notifications from.

How do I retrieve

相关标签:
20条回答
  • 2020-11-22 06:08

    I'd like to contribute with one common scenario (in Python 3) and explore a few approaches to it.

    The built-in function open() accepts either relative or absolute path as its first argument. The relative path is treated as relative to the current working directory though so it is recommended to pass the absolute path to the file.

    Simply said, if you run a script file with the following code, it is not guaranteed that the example.txt file will be created in the same directory where the script file is located:

    with open('example.txt', 'w'):
        pass
    

    To fix this code we need to get the path to the script and make it absolute. To ensure the path to be absolute we simply use the os.path.realpath() function. To get the path to the script there are several common functions that return various path results:

    • os.getcwd()
    • os.path.realpath('example.txt')
    • sys.argv[0]
    • __file__

    Both functions os.getcwd() and os.path.realpath() return path results based on the current working directory. Generally not what we want. The first element of the sys.argv list is the path of the root script (the script you run) regardless of whether you call the list in the root script itself or in any of its modules. It might come handy in some situations. The __file__ variable contains path of the module from which it has been called.


    The following code correctly creates a file example.txt in the same directory where the script is located:

    filedir = os.path.dirname(os.path.realpath(__file__))
    filepath = os.path.join(filedir, 'example.txt')
    
    with open(filepath, 'w'):
        pass
    
    0 讨论(0)
  • 2020-11-22 06:09

    I will try tackling a few variations on this question as well:

    1. finding the path of the called script
    2. finding the path of the currently executing script
    3. finding the directory of the called script

    (Some of these questions have been asked on SO, but have been closed as duplicates and redirected here.)

    Caveats of Using __file__

    For a module that you have imported:

    import something
    something.__file__ 
    

    will return the absolute path of the module. However, given the folowing script foo.py:

    #foo.py
    print '__file__', __file__
    

    Calling it with 'python foo.py' Will return simply 'foo.py'. If you add a shebang:

    #!/usr/bin/python 
    #foo.py
    print '__file__', __file__
    

    and call it using ./foo.py, it will return './foo.py'. Calling it from a different directory, (eg put foo.py in directory bar), then calling either

    python bar/foo.py
    

    or adding a shebang and executing the file directly:

    bar/foo.py
    

    will return 'bar/foo.py' (the relative path).

    Finding the directory

    Now going from there to get the directory, os.path.dirname(__file__) can also be tricky. At least on my system, it returns an empty string if you call it from the same directory as the file. ex.

    # foo.py
    import os
    print '__file__ is:', __file__
    print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)
    

    will output:

    __file__ is: foo.py
    os.path.dirname(__file__) is: 
    

    In other words, it returns an empty string, so this does not seem reliable if you want to use it for the current file (as opposed to the file of an imported module). To get around this, you can wrap it in a call to abspath:

    # foo.py
    import os
    print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
    print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))
    

    which outputs something like:

    os.path.abspath(__file__) is: /home/user/bar/foo.py
    os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar
    

    Note that abspath() does NOT resolve symlinks. If you want to do this, use realpath() instead. For example, making a symlink file_import_testing_link pointing to file_import_testing.py, with the following content:

    import os
    print 'abspath(__file__)',os.path.abspath(__file__)
    print 'realpath(__file__)',os.path.realpath(__file__)
    

    executing will print absolute paths something like:

    abspath(__file__) /home/user/file_test_link
    realpath(__file__) /home/user/file_test.py
    

    file_import_testing_link -> file_import_testing.py

    Using inspect

    @SummerBreeze mentions using the inspect module.

    This seems to work well, and is quite concise, for imported modules:

    import os
    import inspect
    print 'inspect.getfile(os) is:', inspect.getfile(os)
    

    obediently returns the absolute path. For finding the path of the currently executing script:

    inspect.getfile(inspect.currentframe())
    

    (thanks @jbochi)

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

    When you import a module, yo have access to plenty of information. Check out dir(a_module). As for the path, there is a dunder for that: a_module.__path__. You can also just print the module itself.

    >>> import a_module
    >>> print(dir(a_module))
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
    >>> print(a_module.__path__)
    ['/.../.../a_module']
    >>> print(a_module)
    <module 'a_module' from '/.../.../a_module/__init__.py'>
    
    0 讨论(0)
  • 2020-11-22 06:11

    Here is a quick bash script in case it's useful to anyone. I just want to be able to set an environment variable so that I can pushd to the code.

    #!/bin/bash
    module=${1:?"I need a module name"}
    
    python << EOI
    import $module
    import os
    print os.path.dirname($module.__file__)
    EOI
    

    Shell example:

    [root@sri-4625-0004 ~]# export LXML=$(get_python_path.sh lxml)
    [root@sri-4625-0004 ~]# echo $LXML
    /usr/lib64/python2.7/site-packages/lxml
    [root@sri-4625-0004 ~]#
    
    0 讨论(0)
  • 2020-11-22 06:15
    import a_module
    print(a_module.__file__)
    

    Will actually give you the path to the .pyc file that was loaded, at least on Mac OS X. So I guess you can do:

    import os
    path = os.path.abspath(a_module.__file__)
    

    You can also try:

    path = os.path.dirname(a_module.__file__)
    

    To get the module's directory.

    0 讨论(0)
  • 2020-11-22 06:16

    If you want to retrieve the package's root path from any of its modules, the following works (tested on Python 3.6):

    from . import __path__ as ROOT_PATH
    print(ROOT_PATH)
    

    The main __init__.py path can also be referenced by using __file__ instead.

    Hope this helps!

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