sebast26
sebast26

Reputation: 1792

Clean imports from packages in Python

I have a following project structure:

project
|----app.py
|----package
     |---__init__.py
     |---module.py
     |---module2.py
     |---module3.py
     |---....

My __init__.py file currently is empty. In module.py I have a definition of a class:

class UsefulClass:
    ...

And in other modules similar definitions as well. My app.py looks like this:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from package.module import UsefulClass
from package.module2 import UsefulClass2
...

usefulclass = UsefulClass()
usefulclass2 = UsefulClass2()
....

My question is: how can I replace this from package.module... import UsefulClass statements? Even now, I have only 4 modules defined and this imports starting to look ugly. Can I import them in __init__.py file and then just use import package in app.py? I have tried that and it gives me an error.

I am looking for a clean and elegant solution.

Upvotes: 1

Views: 3569

Answers (1)

abarnert
abarnert

Reputation: 365737

In Python 3:

package/__init__.py:

from .foo import bar

package/foo.py:

bar=0

app1.py:

import package
print(package.bar)

app2.py:

from package import bar
print(bar)

Either way, this prints 0, just as you want.

In Python 2, just change from .foo import bar to from foo import bar.

(In fact, the 2.x code often works in Python 3, but it's not correct, and in some edge cases it will fail. For example, if you have a bar.py at the same level as the app, you'll end up with bar being that module, instead of 0.)

In real life, you probably want to specify a __all__ from each package and module that you might ever from foo import … (if for no other reason than to allow to test things at the interactive interpreter with from foo import *).

It sounds like you're saying you already tried this, and got an error. Without knowing exactly what you tried, and what the error was, and which Python version you're using, I have no idea what in particular you might have gotten wrong, but presumably you got something wrong.


The .foo specifies a package-relative import. Saying from .foo import bar means "from the foo module in the same package as me, import bar". If you leave off the dot, you're saying "from the foo module in the standard module path, import bar".

The tutorial section on Intra-package References (and surrounding sections) gives a very brief explanation. The reference docs for import and the import system in general give most of the details, but the original proposal in PEP 328 explains the details, and the rationale behind the design, a lot more simply.

The reason you need to leave off the dot in 2.x is that 2.x didn't have any way to distinguish relative and absolute imports. There's only from foo import bar, which means "from the foo module of the same package as me, or, if there is no such module, the one in the standard module path, import bar".

Upvotes: 1

Related Questions