[Tutor] relative imports within a package?

Steven D'Aprano steve at pearwood.info
Sat Nov 7 20:17:12 EST 2015


On Sat, Nov 07, 2015 at 04:09:19PM -0600, James Hartley wrote:
> The Python 3 tutorial discusses relative imports at:
> 
> https://docs.python.org/3/tutorial/modules.html#intra-package-references
> 
> I have the following directory structure for a package in development:
> 
> + outer_package/
>      + __init__.py
>      + inner_package
>      |     + __init__.py
>      |     + myclass.py
>      + collateral_directory
>            + arbitrary_tool.py


As shown above, "collateral_directory" is not part of the package. It is 
just a directory with stuff in it. The fact that the "stuff" happens to 
include a Python script is irrelevant.

If "arbitrary_tool.py" is actually independent of outer_package, you 
should have this layout:


+ arbitrary_tool.py
+ outer_package/
    + __init__.py
    + inner_package
    |     + __init__.py
    |     + myclass.py


where the enclosing directory is part of your PYTHONPATH. Then, in 
arbitrary_tool, you say:

    from outer_package import MyClass
    # assuming outer_package has already made this available

or 

    from outer_package.inner_packages import MyClass
    # assuming inner_package has made this available
    # which you have done

or 

    from outer_package.inner_package.myclass import MyClass

whichever you prefer.

If arbitrary_tool is not independent of outer_package, then you should 
convert it to a package with this layout:


+ outer_package/
    + __init__.py
    + inner_package
    |     + __init__.py
    |     + myclass.py
    + collateral_directory
          + __init__.py
          + arbitrary_tool.py


__init__.py may be an empty file, it just has to exist. Now 
collateral_directory is a sub-package, and you can do things like this:


# from outer_package.__init__
import collateral_directory.arbitrary_tool

# from inner_package.myclass (but watch out for circular imports)
from ..collateral_directory.arbitrary_tool import Spam


But if arbitrary_tool is part of the package, and it is the only file in 
collateral_directory, why mess about with a subpackage? Lay your package 
out like this:

+ outer_package/
    + __init__.py
    + arbitrary_tool.py
    + inner_package
    |     + __init__.py
    |     + myclass.py

and inside arbitrary_tool say:

from inner_package.myclass import MyClass


(P.S. this is Python, not Java. There is no requirement to put every 
class in its own file, in fact doing so is mildly discouraged. Does 
MyClass truly deserve its own file? If not, you may be able to simplify 
your package structure even more.)



-- 
Steve


More information about the Tutor mailing list