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 to import other modules, so that even when the "top_package" changes name nothing breaks.
I am not in favour of using the relative import like "..level_one_a" as relative path will be different to each python file below. I am looking for a way that:
- Each python file can have the same import statement for the same module in the package.
A decoupling reference to "top_package" in any .py file inside the package, so whatever name "top_package" changes to, nothing breaks.
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 main.py
Put your package and the
main
script into an outer container directory, like this:When
main.py
is run, its parent directory (container
) will be automatically added to the start ofsys.path
. And sincetop_package
is now in the same directory, it can be imported from anywhere within the package tree.So
hello_world.py
could importlevel_one_b/my_lib.py
like this: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 removetop_package/__init__.py
, and you would be left with efectively the same arrangement.The previous import statement would then change to:
and you would be free to rename
top_package
however you wished.This works from within a library module:
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 itimport top_leve
l you can then referencetop_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/)
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: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.
This should do the job:
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.