How to reference to the top-level module in Python inside a package?

前端 未结 5 563
醉梦人生
醉梦人生 2021-02-01 17:51

In the below hierachy, is there a convenient and universal way to reference to the top_package using a generic term in all .py file below? I would like to have a consistent way

相关标签:
5条回答
  • 2021-02-01 18:11

    I believe #2 is impossible without using relative imports or the named package. You have to specify what module to import either by explicitly calling its name or using a relative import. otherwise how would the interpreter know what you want?

    If you make your application launcher one level above top_level/ and have it import top_level you can then reference top_level.* from anywhere inside the top_level package.

    (I can show you an example from software I'm working on: http://github.com/toddself/beerlog/)

    0 讨论(0)
  • 2021-02-01 18:12

    This should do the job:

    top_package = __import__(__name__.split('.')[0])
    

    The trick here is that for every module the __name__ variable contains the full path to the module separated by dots such as, for example, top_package.level_one_a.my_lib. Hence, if you want to get the top package name, you just need to get the first component of the path and import it using __import__.

    Despite the variable name used to access the package is still called top_package, you can rename the package and if will still work.

    0 讨论(0)
  • 2021-02-01 18:22

    This works from within a library module:

    import __main__ as main_package
    TOP_PACKAGE = main_package.__package__.split('.')[0]
    
    0 讨论(0)
  • 2021-02-01 18:35

    Put your package and the main script into an outer container directory, like this:

    container/
        main.py
        top_package/
            __init__.py
            level_one_a/
                __init__.py
                my_lib.py
                level_two/
                    __init__.py
                    hello_world.py
            level_one_b/
                __init__.py
                my_lib.py
    

    When main.py is run, its parent directory (container) will be automatically added to the start of sys.path. And since top_package is now in the same directory, it can be imported from anywhere within the package tree.

    So hello_world.py could import level_one_b/my_lib.py like this:

    from top_package.level_one_b import my_lib
    

    No matter what the name of the container directory is, or where it is located, the imports will always work with this arrangement.

    But note that, in your original example, top_package it could easily function as the container directory itself. All you would have to do is remove top_package/__init__.py, and you would be left with efectively the same arrangement.

    The previous import statement would then change to:

    from level_one_b import my_lib
    

    and you would be free to rename top_package however you wished.

    0 讨论(0)
  • 2021-02-01 18:36

    You could use a combination of the __import__() function and the __path__ attribute of a package.

    For example, suppose you wish to import <whatever>.level_one_a.level_two.hello_world from somewhere else in the package. You could do something like this:

    import os
    _temp = __import__(__path__[0].split(os.sep)[0] + ".level_one_a.level_two.hello_world")
    my_hello_world = _temp.level_one_a.level_two.hello_world
    

    This code is independent of the name of the top level package and can be used anywhere in the package. It's also pretty ugly.

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