the demise of 'from foo import * and its implications?

Tim Hochberg tim.hochberg at ieee.org
Sat Mar 3 11:24:30 EST 2001


"Robin Becker" <robin at jessikat.fsnet.co.uk> wrote in message

[SNIP]

> If we really want to improve visibility we could try to make
>
> >>> def bingo(a):
> ...     if a<=1: return 0
> ...     return bingo(a-1)*a
> ...
>
> work naively, but I'm fairly sure this will be rejected as unpythonic or
> somesuch.


?????

In what sense doesn't this work now? Under 2.0 or 1.5.2 or even, I think,
under 0.9 this 'works' in the sense that it iterates for a while then
returns 0. If one replaces "return 0" with "return 1" it even returns the
factorial as I assume it should.

What doesn't work is the following:

def spam(n):
   def fact(a):
      if a <= 1: return 1
      else: return fact(a-1)*a
   return fact(n) + 42

With the current three level scope rule this fails, so a function that works
fine when defined at the top level fails miserably when defined at an
intermediate level. Given your earlier statement that:

>my preference would be that statements legal in one context should be
>legal in another where they make sense.

This seems like it would be of concern to you as well.

My understanding is we can have two of the following three options:

1. Decent performance (~current performance)
2. "Real" lexical scoping
3. Unrestricted use of  "from X import *" at other than module scope.

Given those choices I'd choose 1 and 2. Which is fortunate for me, since
that's what were going to get anyway.

----------------------------------------------------

Going off on a tangent: In listening to the various debates here, and when I
was spying on PythonDev, I've come to the conclusion that "from X import *"
was a mistake to begin with. It has it's uses, but there are other ways to
satisfy them without the downsides of "import *".

"import *" is used, in essence, to extend the list of __builtins__ that one
sees in a module or in interactive mode. This is commonly used with some
windowing toolkits for example, where importing the contents an item at a
time is too painful (using from X import a,b,c,d....) and where the names of
the toolkit's contents have been constructed not to stomp on the local
namespace.

The problems with "import *" include:
* May inadvertenly stomp on local namespace
* Can't easily reload module contents (OK, so it's not that hard,  but it's
hard to explain sometimes).
* Gives the compiler a headache in inner scope.

Let's consider another approach that I believe satisfies the current uses
for "import *" without its drawbacks.

<COUNTERFACTUAL WORLD>
__module_builtins__ is a list of modules, each of which is searched in turn
when lookup fails at the global (aka module) scope. Initally,
__module_builtins__ equals [__builtins__], so the behaviour is the same as
in the real world, except for going through an additional layer. But if
additional modules are appended to __module_builtins__, they are each
searched in turn to resolve a name lookup.

   import spam as * # I don't defend this syntax, it's only for illustration

Is shorthand for:

   import spam
   __module_builtins__.append(spam)
  del spam

So, to make all of the wxPython stuff available one types:

   import wxPython.wx as *
   class MyApp(wxApp):
       # ....

This looks first in the module dictionary, then in __builtins__ (since it's
the first entry in __module_builtins__) then in wxPython.wx, where it would
find wxApp. It involves extra lookups over "import *", but if anyone needs
speed in a particular place, they can import directly into the local scope,
as they do now.

</COUNTERFACUTAL WORLD>

The nice things about this approach include:

* It can't stomp on local variables
* Reload just works.
* You can use it wherever you want without giving the compiler fits since is
only affects __module_builtins__, not the local scope.
* You can cleanly remove imported  modules by deleting them from
_builtin_modules__, something that's difficult to do with import *
* Others to numerous to mention.

However, at this point I imaging it's many years to late, and "from spam
import *" is here to stay.

If you've put up with my rambling to this point I congratulate you.

Ramblin on,

-tim








.





More information about the Python-list mailing list