17

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.)

1 Answer 1

20

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.

Sign up to request clarification or add additional context in comments.

Oh, super helpful, thanks! In the __init__.py you linked to, 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?
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.

Your Answer

Draft saved
Draft discarded

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.