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.