dshanahan
dshanahan

Reputation: 744

namespace with submodule imports

I am wanting to use a simple list comprehension to set __all__ for the modules in my package. I am noticing that when I import something from one of my own modules that the module name is added to the namespace, not just what I am importing. This is not the same when as when importing builtin or third-party packages.

- foo
  - __init__.py
  - bar.py
  - baz.py

__init__.py

import os as _os

from numpy.random import randint as _randint

import foo.bar as _bar

from foo.baz import foobar

__all__ = [x for x in globals() if not x.startswith('_')]

I expect:

>>> import foo
>>> foo.__all__
['foobar']

But I get:

>>> import foo
>>> foo.__all__
['bar', 'baz', 'foobar']

I know I could expand my list comprehension for __all__ to filter out ModuleType but I am wondering why the behavior is different for my own modules. I would really like to be able to use a leading underscore to handle this as I can with other packages. I have also tried using dir(), locals(), and vars() instead of globals() but the result is the same.

Update
Out of curiosity, I also imported foobar into bar.py and printed globals() and 'bar' was not included. So, it appears my modules are only added to the namespace within __init__.py files?

Upvotes: 1

Views: 820

Answers (1)

alex_noname
alex_noname

Reputation: 32153

All credits to @MisterMiyagi in comments.

I will only confirm this with a quote from the official documentation 5.4.2. Submodules:

When a submodule is loaded using any mechanism [...] a binding is placed in the parent module’s namespace to the submodule object.

For example in your case, if package foo has a submodule bar, after importing foo.bar, foo will have an attribute bar which is bound to the submodule foo.bar.

Upvotes: 1

Related Questions