Package setup best practice style question

Steven D'Aprano steve at pearwood.info
Sat May 28 13:00:15 EDT 2016


On Sun, 29 May 2016 02:15 am, Gerald Britton wrote:

> suppose I have a simple python project setup like this:
> 
> Project diectory
>      prog.py
>      pkg directory
>           __init__.py
>           mod1.py
>                class A:

If this is a single project, why do you set it up like this? Is there a
reason why you don't just have:

prog.py  # contains class A

or even:

prog.py
mod1.py  # contains class A


Or if the project is so big it needs to be a package, make it executable:

prog/
    __init__.py
    mod1.py
    __main__.py


This layout is now executable using:

python -m prog

which automatically calls __main__.py.


But if you don't have a good reason for using a package, don't use a
package. Use the simplest project layout that solves your problem.

But for the rest of my comments, I'm going to assume that you DO have a good
reason.



> In order to have class A (unqualified) available from prog.py, there are a
> few options that I know about.  I'm currently considering two of them and
> would like some feedback on best practices.
> 
> 1. in pkg.__init__.py add:
> 
>        from pkg.mod1 import A

This kinda-sorta defeats the purpose, or at least one purpose, of using a
package. Which is fine, so long as you understand that's what you are
doing.

Generally speaking, one of the purposes of using a package layout is to
allow unused sub-modules to be left unloaded unless needed. So pkg.mod1
doesn't get loaded unless you need it, in which case you explicitly call 

import pkg.mod1

or 

from pkg.mod1 import A

as you prefer. By putting that import in the pkg __init__ file, you're
making it automatically occur as soon as pkg is imported. Is that what you
intend? If so, then it is fine, and feel free to do it.

But in that case, why not just move class A into pkg/__init__.py?


>     in prog.py add:
> 
>        from pkg import A

*shrug* This entirely depends on the purpose and use of pkg. When you give
generic, meaningless names, I can only respond with wishy-washy, sit-on-
the-fence generic advice.

If the appropriate API is for callers to say:

from pkg import A

then this is the right way to design your package. But if the right API is:

from pkg.mod1 import A

then don't do it this way, instead do it as follows.


> 2. leave __init__.py empty
>     in prog.py add:
> 
>          from pkg.mod1 import A
> 
> 
> Is there a preference or best practice that would indicate to prefer
> method
> 1 or method 2?  Are there methods 3, 4, 5, ... that I should consider that
> are even better?

One purpose of using a package is to have alternative implementations. For
instance I have a package which has to support Python 2.4 where the "with"
statement is not available, so I design it like this:

package/
    __init__.py
    module.py
    module24.py

Since the user doesn't choose which implementation to use, I have this in
the init file:


try:
    from module import thing
except SyntaxError:
    from module24 import thing


and then the caller uses:

from package import thing

and is none the wiser.

On the other hand, if the user was supposed to choose, then I would have
then call:

from package.redblack import Tree
from package.avl import Tree
from package.scapegoat import Tree

and let the user choose which implementation they wanted.


-- 
Steven




More information about the Python-list mailing list