Module Structure/Import Design Problem

Rafe rafesacks at gmail.com
Mon Nov 24 05:40:01 EST 2008


On Nov 22, 2:39 am, Stef Mientki <stef.mien... at gmail.com> wrote:
> Gabriel Genellina wrote:
> > En Thu, 20 Nov 2008 17:36:11 -0200, Stef Mientki
> > <stef.mien... at gmail.com> escribió:
>
> >>>> I'm not an expert, I even don't fully understand your problem,
> >>>> but having struggled with imports in the past,
> >>>> I've a solution now, which seems to work quit well.
>
> >>> That's not very helpful, is it? Were you planning to keep the solution
> >>> secret?
>
> >> sorry slip of the keyboard ;-)
> >>http://mientki.ruhosting.nl/data_www/pylab_works/pw_importing.html
>
> > May I reiterate my criticism to your "solution" posted last week?
>
> You're welcome,
> if there are better (even more important simpler) solutions, I'm in.> I don't think extending sys.path to include every directory under your
> > project is a good idea. Basically, you're flattening the directory
> > layout, removing any structure, like it was before Python 1.5 added
> > package support.
> > It is like dumping all your modules in a single directory, with no
> > hierarchy and lots of name conflicts.
>
> Well I started at 2.4 and now arrived at 2.5, so I don't know what it
> was at 1.5.
> And I'm probably going to stay at 2.5 for a long time, upgrading is one
> of the few (maybe the only) disadvantages of Python ;-)
> For Python, I guess you're right, all files are in one flat directory, ...
> ... but it's just 1 program, so what's the objection ?
> For the program itself, which is highly dynamic, it can find sets of
> python-files in certain subpaths,
> so that's quit ordered I think ?
>
> > Worse: because your proposal makes the same file reachable under many
> > different names, the *same* source module will generate *different*
> > module objects stored as *different* entries in sys.modules. Globals
> > don't work anymore, subclasses aren't subclasses... lots of problems.
>
> Could you explain this a little more ...
> ... I'm just adding every subpath to the Pythonpath,
> so in my ignorant believe, every module is imported the same way, but I
> might be wrong.
> " Globals not working" , a good program doesn't have any globals ( said
> a non-programmer ;-)
> Subclasses aren't subclasses ? ( I always derive subclasses in the
> module itself, or in the same directory as the parentclass)> Relative imports (PEP328 [1]) were introduced -among other things- as
> > an attempt to avoid such problems. You're going in the opposite
> > direction. Please stop doing that - or at least keep us informed of
> > where you work!
>
> > [1]http://www.python.org/dev/peps/pep-0328
>
> Sorry I don't understand all that pep-talk (I'm not a programmer ;-)
> I read it starts with " For the second problem, it is proposed that all
> import statements be absolute by default (searching sys.path only) with
> special syntax (leading dots) for accessing package-relative imports."
> I think that's exactly what I'm doing: absolute imports.
>
> Please explain in simple language what I'm all doing wrong,
> or how I get a better solution.
>
> thanks,
> Stef

Hi Stef,

I'm not a programmer either (and still in my first year of using
python), so I understand a bit of where you are coming from. There is
some good info in this thread, but put simply...

- There is very rarely a reason to add things to the python path since
only the module, or package top folder, needs to be in the pthon path
for everything to work (which really means the parent folder is in the
path as python looks in the folder on the path for modules and
packages). If python can find the top folder in a package (folder
structure with __init__.py files in each folder), then you can access
everything easily.

- Use the simplest form of import that works for what you need. From
my reading on python standards, this is the simplest to use and read:
>>> import foo.bar as bar

Only use 'as' if the path is really long and you don't want to type it
every time (I often use modules if they are only two levels deep
without 'as'. It makes the code easier to read in many cases). It's
like creating a shortcut or alias.

The next most common is probably the "from ... import ..." form.

I'd say the general rule-of-thumb is to avoid situations where you
don't know where a name comes from. This is why "from foo import *" is
generally evil. I have only found a single case to use this and that
is when I have a globals module that is designed for use with 'import
*'. 99% of the time I use the standard 'import <module path>'

Examples:

If I have:
    package
        __init__.py  # Can be empty
        subpackage
            __init__.py  # Can be empty
            module.py    # has "ClassA" in it

I will almost always do this:
>>> import package.subpackage.module as module
>>> module.ClassA()

This makes it easy to understand where it is coming from (or at the
very least offers a clue to look for import statements). Worse is:
>>> from package.subpackage import module
>>> module.ClassA()

I'm not sure if there is any difference to the above, but again, I try
to use the simplest form possible, and this is just a more complicated
version of the same thing (IMO). It isn't immediately obvious if
module is a module, class, function, or other object in this last
case. However, the plan import statment only allows module imports, so
it IS obvious. Only use "from ... import ..." in very special cases
where you need a module attribute, not a module.

The next example is bad (again, IMO):
>>> from package.subpackage.module import ClassA
>>> ClassA()

It removes the name space and makes it harder to guess where it is
from. There is very little chance of overriding "module.ClassA", but
it would be easy to override just "ClassA":

Even worse!:
>>> from package.subpackage.module import ClassA as Foo
>>> Foo()

Talk about hiding the truth!


Hope this helps. importing isn't nearly as hard as it seems when first
using it. Just put your package in the python path and start importing
away. It should be quite logical if kept simple.

If you have to add things to the python path using sys.path, only add
the top level of the package.

- Rafe



More information about the Python-list mailing list