Reputation: 21
For example in multiprocessing
package we can import class Process
using from multiprocessing import Process
. Why not from multiprocessing.context import Process
where it really belongs?
In fact, I found that they are the same. Why?
Upvotes: 2
Views: 882
Reputation: 250951
Adding imports to __init__
is usually done to shorten the import paths and define a public interface. multiprocessing.context import Process
is an internal interface and can change in future without maintaining any backwards compatibility.
On the other hand multiprocessing import Process
is the documented public interface and won't change to break backwards compatibility.
You could see that __all__
under context.py
is empty meaning it has no public interface and you should not import from it in your application as it can change in future without any warnings.
__all__ = [] # things are copied from here to __init__.py
Related section on this from PEP-008:
Any backwards compatibility guarantees apply only to public interfaces. Accordingly, it is important that users be able to clearly distinguish between public and internal interfaces.
Documented interfaces are considered public, unless the documentation explicitly declares them to be provisional or internal interfaces exempt from the usual backwards compatibility guarantees. All undocumented interfaces should be assumed to be internal.
To better support introspection, modules should explicitly declare the names in their public API using the
__all__
attribute. Setting__all__
to an empty list indicates that the module has no public API.Even with
__all__
set appropriately, internal interfaces (packages, modules, classes, functions, attributes or other names) should still be prefixed with a single leading underscore.An interface is also considered internal if any containing namespace (package, module or class) is considered internal.
Imported names should always be considered an implementation detail. Other modules must not rely on indirect access to such imported names unless they are an explicitly documented part of the containing module's API, such as os.path or a package's
__init__
module that exposes functionality from submodules.
The famous requests
library has a really nice public interface in my opinion and you could see that it is being done by importing most of things in the __init__.py
file. And you're going to find that it is also documented based on the imports under __init__.py
file.
Upvotes: 2
Reputation: 5193
from multiprocessing import Process
works because Process
is imported into the __init__.py
of the multiprocessing
package. For example, in your shell, type the following code:
import multiprocessing
with open(multiprocessing.__file__, 'r') as f:
print(f.readlines())
You'll see the lines:
from . import context
#
# Copy stuff from default context
#
globals().update((name, getattr(context._default_context, name))
for name in context._default_context.__all__)
__all__ = context._default_context.__all__
So yes, it's the same thing.
Upvotes: 1