[Python-Dev] Making submodules available when importing top one

Eric Snow ericsnowcurrently at gmail.com
Wed Oct 16 21:04:51 CEST 2013


On Wed, Oct 16, 2013 at 10:26 AM, Facundo Batista
<facundobatista at gmail.com> wrote:
> (all this using Python 3.4.0a3+)
>
> In the stdlib, I see that (as an example):
>
>>>> import os
>>>> os.path.abspath
> <function abspath at 0xb7123734>
>>>> os.path
> <module 'posixpath' from '/.../python/trunk/Lib/posixpath.py'>
>
>
> However, for other (newer) modules:
>
>>>> import urllib
>>>> urllib.requests.urlopen
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> AttributeError: 'module' object has no attribute 'requests'
>>>> import concurrent
>>>> concurrent.futures
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> AttributeError: 'module' object has no attribute 'futures'
>
>
> So, is there a reason to not expose the submodules in the top module?
> This should be fixed?

-1

When you import a submodule the parent is imported first, the
submodule second, and the submodule is bound as an attribute of the
parent.  Then the parent is bound to the module where the import
happened.  This is always the case (and not particular to os.path).

For example, let's suppose you have these two files (plus a spam package):

<ham.py>
  import spam.eggs

<sausage.py>
  import ham
  import spam

When you run "python -c 'import sausage'", here's what happens:

1. ham is loaded:
    a. spam is loaded and added to sys.modules.
    b. eggs is loaded (as "spam.eggs") and added to sys.modules (as
"spam.eggs").
    c. the "eggs" attribute of spam (spam.eggs) is bound to the module
at sys.modules["spam.eggs"].
    d. the "spam" attribute of the [currently loading] ham module
(ham.spam) is bound to the module at sys.modules["spam"].
2. sausage is loaded:
    a-c. (already done when ham was imported)
    d. the "spam" attribute of the [currently loading] sausage module
(sausage.spam) is bound to the module at sys.modules["spam"].

So now you could use "spam.eggs.<some attr>" in sausage even though
you did not import "spam.eggs" there.

It just happens that during interpreter startup some module did
"import os.path", so the submodule is still bound to os.  If
urllib.requests had been imported during startup (or in another
module), then your example would have worked.

Guido's response covers just about everything else I was going say.
If you really need to auto-import submodules of modules you don't
control, you can write your own importer to do it.  The import system
is pretty easily extended.  In this case, however, I doubt that's
warranted.

-eric


More information about the Python-Dev mailing list