other python ideas

Andrew Dalke dalke at acm.org
Tue Apr 10 00:01:47 EDT 2001


Douglas Alan:
>alias StringIO = cStringIO
>try:
>   dummy = StringIO::someObject
>except ImportError:
>   alias StringIO = StringIO

Doesn't this introduce the same problems you have with import?
Specifically, you may end up with lots of "alias" statements
which are unneeded by the module?

It's also somewhat awkward in that you need to know an object
inside of the cStringIO/StringIO module for which to test.

>or
>
>try:
>   StringIO = __import__("cStringIO")
>except ImportError:
>   StringIO = __import__("StringIO")

Not as nice looking with more complicated imports

try:
  import Some.Patented.Module as ModuleX
except ImportError:
  import My.Non.Patented.But.Slower.Module as ModuleX

where you'll need

  ModuleX = __import("Some.Patented.Module").Patented.Module

But then, I've never liked that aspect of __import__.

Regardless, then in your proposal later on you would use

   StringIO::StringIO

That means the implementation would need to first check if
StringIO is defined in the module and, if not, do the
__import__.


>> Or the not so common practice of
>> [call trace example]

>The same way you have just done it above, only without the import
>statement and replace
>
>   math = TraceCalls(math)
>
>with
>
>   math = TraceCalls(__import__("math"))
>
>If in "math::foo", "math" turns out to refer an object other than a
>module object, the language can still go with the flow, just like in
>normal Python.

So your construct of "X::Y" acts like

  if X exists:
    return X.Y
  else:
    __import__(X).Y

What about multilevel imports, say, xml.sax.handler?  Could I use

  xml.sax::handler.ContentHandler

or would I need to do

  xml::sax::handler.ContentHandler ?

What if xml.sax is really

class sax:
  def __getattr__(self, name):
    import new
    return new.module(name)


>Personally, I hate maintaining import lists.  As a general
>rule, I think it is bad to have to maintain the same information in
>two different places.

But it isn't the same information.  One says that a name refers
to a module, or a class, or an instance, or a function.  The
other one says what to do with the name.

 def what_is(obj):
   print "This is", obj.__doc__

 import math
 what_is(math)

 math = math.cos
 what_is(math)

 class math:
   pass
 what_is(math)

 math = math()
 what_is(math)

Hmm.  Thinking about this.  How would you implement
  import math
  what_is(math)
in your scheme?  Perhaps as
  what_is(math::)
?

>  Having to do so results in dead code that loads unused modules.

I mentioned your "alias" has the same problem.

There are tools which address unneeded imports.  One was announced
just a few days ago.  A couple years ago I worked on mods to
kwparser's lint program to support 1.5 syntax and gave Guido a
list of a few dozen module references to delete.

Even with this there will be cruft functions, classes, etc.
which won't be fixed with this proposal, so it tries to solve
part of the problem without really addressing the whole thing.
(Oh, and I helped with the code coverage program distributed
in the Tools section to help that more general case :)

>Also, I know people who won't use Python because they
>want to be able to reload modules reliably, as you can on a Lisp
>Machine.

The quick answer is to let them work on Lisp Machines.  Now
consider:

import spam

def f(x, eggs = spam.eggs):
  return eggs(x) * eggs(x+1)

Because f's default value for eggs is defined at module import
time there is no way to reload(spam) and have f's function
redefined.  Instead, you need to do a reload of this module as
well.

Your proposal would change this to

def f(x, eggs = spam::eggs):
  return eggs(x) * eggs(x+1)

but still have the same problem that a reload(spam) won't
rebuild f.  So you don't fully solve the problem you want
to solve.

It's even worse when you have:

# viking.py
import spam
class Parrot:
  def __init__(self, eggs = spam.eggs):
    self.eggs = eggs
  def f(self, x):
    return self.eggs(x) * self.eggs(x+1)

 ----
% python
>>> import viking
>>> bird = Viking.Parrot()
>>> # oops! edit spam to fix a bug in eggs
>>> import eggs
>>> reload(eggs)
>>> reload(viking)  # just to be safe
>>> bird.f(9)
# returns wrong answer because bird keeps a reference to the *old*
# Viking.Parrot definition and the instance keeps a reference to
# the *old* eggs.
>>>

So you are only fixing one part of a larger issue, which is
rebuilding everything in Python dependent on a module.

> Unfortunately, the Common Lisp module system is unbearably
> complex.

Whereas Python's system is quite easy to explain and works
just about like everything else namespace related.

And I must confess to not knowing anything other than the
most elementary parts of Lisp.  Then again, I can point to
precisely 1 person in all of computational biology and
chemistry which use it... which is as many people as I know
using Prolog or Ruby, and 1/2 the number I know of who have
used Smalltalk.  I suspect that means something.

                    Andrew
                    dalke at acm.org






More information about the Python-list mailing list