12

Let's say I have a module foo and a submodule foo.bar. If I want to use a method in foo.bar, do I need to import foo.bar directly or is importing foo sufficient?

For example, the following throws an error:

import foo

foo.bar.my_method()

and the following works:

import foo.bar

foo.bar.my_method()

But I'm not sure if this is generally what's needed, or if there's something wrong with my code itself. (I would think importing the submodule directly is generally needed... But I could have sworn I've seen code where it's not imported directly and still works fine.)

Joe
  • 123
  • 4

1 Answers1

16

If I want to use a method in foo.bar, do I need to import foo.bar directly or is importing foo sufficient?

You'll need to import the submodule explicitly. Executing import foo.bar will automatically import the parent module foo, and necessarily bind the name foo, but the reverse is not true.

But I could have sworn I've seen code where it's not imported directly and still works fine

Yes. Sometimes accessing a submodule works without the explicit import. This happens when a parent module itself imports the submodules. Never rely on that unless it's documented, because it may be an implementation detail and could change without warning after a library version upgrade.

As an example of a popular library which demonstrates both behaviors, look at requests==2.18.4. This package has submodules called sessions and help (amongst others). Importing requests will make requests.sessions available implicitly, yet requests.help will not be available until explicitly imported. You'll find when the source code of the package init is executed that the sessions submodule gets imported, but the help submodule does not.

This makes sense, because subsequent use of foo.bar requires an attribute access on an existing foo object. Note that from foo.bar import something does not bind the name foo nor foo.bar, though both modules foo and foo.bar are imported and cached into sys.modules.

wim
  • 338,267
  • 99
  • 616
  • 750
  • Oh, super helpful, thanks! In the [`__init__.py` you linked to](https://github.com/requests/requests/blob/v2.18.4/requests/__init__.py#L101), what's the reason for `from .sessions import session, Session` if those imports aren't used in the `__init__.py` file directly? Just to make it so that importing `requests.sessions` isn't absolutely necessary? – Joe Apr 04 '18 at 02:40
  • This is likely a convenience - pulling names up into the parent namespace. Library users can now write an import statement `from requests import Session`, that's shorter yet equivalent to `from requests.sessions import Session`. – wim Apr 04 '18 at 02:54