简体   繁体   中英

Why cannot import sub module?

My project structure like this:

/project
    main.py
    /a_module
        __init__.py
        /sub_module
            __init__.py
            some_file.py

main.py

from a_module import main_api

a_module/__init__.py

from sub_module import sub_api

sub_module/__init__.py

from some_file import detail_api

In a_module/__init__.py gives Unable to import 'sub_module' error.

Why I cannot import 'sub_module' ?

When I change to the relative path solve the error.

from .sub_module import sub_api

But I don't understand, does __init__.py design for public the API of the module? Why don't treat sub_module as a module instead of a directory? it's such a bad design to me...

__init__.py is executed when you import the package that contains it. But it's not your problem. Your problem is that module imports are always absolute unless explicitly relative. That means that they must chain from some directory in sys.path . By default this includes the working directory, so when you run main.py from within project , it can find a_module , and nothing else.

from sub_module import sub_api

In a_module/__init__.py doesn't work though, because imports are always absolute unless explicitly relative . So that import says "starting from some sys.path root, find a top level package named sub_module and import sub_api from it". Since no such module exists you get an error. from .sub_module import sub_api works because you opted into relative imports, so it doesn't start over from sys.path .

For an example of why you would do this, I'll give you something that broke in our own code back in the Python 2 days before absolute import by default was the law ( from __future__ import absolute_import enabled the Py3 behavior, which is how we fixed it, but despite what the docs say, it was never enabled by default in Py2, the only enabled by default behavior was relative imports). Our layout was:

 teamnamespace/
               module.py
               math/
                    mathrelatedsubmodule.py
                    othermathsubmodule.py

Now, we innocently thought hey, we'll put all our packages under a single shared top level namespace, and subpackages cover broad categories within them, and since we had a lot of additional utilities for basic mathematics, we put them under teamnamespace.math . Problem was, for the non -math modules, like teamnamespace.module , when they did:

import math  # or
from math import ceil

it defaulted to relative lookup, and imported teamnamespace.math as math (a thoroughly useless import, since it was a namespace package only, all the functionality was in the sub-modules), not the built-in math module. In fact, without the Python 3 behavior, there was no reasonable way to get the built-in math module from a module under teamnamespace . Whereas with the Python 3 behavior, you can get either one or both (by aliasing one or the other with as , with no ambiguity:

# Gets built-in
import math

# Gets teamnamespace.math
from . import math

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM