[Python-ideas] Packages and Import

Josiah Carlson jcarlson at uci.edu
Sat Feb 10 00:28:52 CET 2007


"Brett Cannon" <brett at python.org> wrote:
> On 2/9/07, Josiah Carlson <jcarlson at uci.edu> wrote:
> > "Brett Cannon" <brett at python.org> wrote:
> > > On 2/9/07, Ron Adam <rrr at ronadam.com> wrote:
[snip]
> > > >     import module
> > > >     module()
> > > >
> > > > And it would just work.  ;-)
> > > >
> > >
> > > I like this idea.  Makes it very obvious.  You just say "when a
> > > specific module is specified at the command line it is called.  Could
> > > even have it take possibly sys.argv[1:] (which I think was supposed to
> > > turn into sys.args or sys.arg or something at some point).
> > >
> > > What do other people think?
> >
> > I don't like it.  Much of my dislike comes from personal aesthetics, but
> > then there is a logical disconnect.  When an instance of a class is
> > created, its __call__ method is not automatically called. By using the
> > semantic of 'the __call__ function in the module namespace is
> > automatically executed if the module is "run" from the command line', we
> > are introducing a different instance creation semantic (an imported
> > module is an instance of ModuleType).
> 
> But I don't see the leap of how specifying a module to execute on the
> command line is any different than doing ``Class()()`` for
> instantiation with an immediate call.  It would still be a separate
> step.

I feel that there is a disconnect, but maybe it's personal aesthetics
again.


> > I think we should just stick with what has been proposed for *years*, a
> > __main__ function that is automatically executed after the module has
> > been imported if its __name__ == '__main__'.
> 
> But that does not solve the problem Ron has been trying to deal with;
> setting __name__ to __main__ prevents the execution of a module that
> uses relative imports because the import machinery can then no longer
> infer what package the module is in.

I may have missed it, but how are either of the following ambiguous...

    from . import foo
    from ..bar import baz

The leading dot tells me that 'relative to the path of the current
module (or __init__.py module in a package), look for packages/modules
named [everything else without a single leading dot].

Now, I tried the first of those lines in Python 2.5 and I was surpised
that having two files foo and goo, goo importing foo via the first
example above, didn't work.  What is even worse is that over a year ago
I was working on an import semantic for relative imports that would have
made the above do as I would have expected.

This leads me to believe that *something* about relative imports is
broken, but being that I mostly skipped the earlier portions of this
particular thread, I'm not certain what it is.  I would *guess* that it
has to do with the way the current importer comes up with package
relative imports, and I believe it could be fixed by switching to a
path-relative import.

That is, when module goo is performing 'from . import foo', you don't
look at goo.__name__ to determine where to look for foo, you look at
goo.__file__ .  With that change in semantic, both of the above cases
work just fine, including 'from ..bar import baz', even without the
current module being part of a package.  That is, running goo.py in the
following tree would succeed with the above two imports...

    .../
        torun/
            #include __init__.py if you want this to be a package
            goo.py
            foo.py
        bar/
            __init__.py
            baz.py
        #I don't know if it would make sense to require __init__.py here

It is still possible to handle import hooks, as the relative import
stuff is only really applicable to getting the base path from which to
start searching for sub packages (after you have stripped off all
leading periods).

It also naturally leads to a __name__ semantic that Guido had suggested
to me when I was talking about relative imports:

    goo.__name__ == '__main__'
    foo.__name__ == '__main__.foo'
    baz.__name__ == '__main__..bar.baz'

Which could more or less be used with the current importer; it just
needs a special-casing of 'from . import ...' in the __main__ module. 
It may also make sense to do path/__name__ normalization relative to
__main__ for any relative imports, so if in baz.py above you did 'from
..torun import foo', that it gave you the previously existing foo and
not a new copy.

I've got a bunch of code that implements the above name/path semantic,
but it was never tested (being that I was using Python 2.4 at the time,
and relative imports weren't proper syntax).


 - Josiah




More information about the Python-ideas mailing list