Overloading and? was <RE: Should I prefer an external database>

Andrew Dalke adalke at mindspring.com
Fri Apr 25 01:11:26 EDT 2003


Steven Taschuk:
> Hm.  I'm not sure I understand what would make such a language not
> Python.

I believe apologies are due.  It appears I misread flippancy into
your response, so this one of mine is now more serious.

> I agree, of course, that no known Python has such special __and__
> and __or__ methods.  But that no *known* Python works as I
> suggested does not mean that no *possible* Python works thus.
> (Consider that not long ago the yield statement was not part of
> any known Python.  And imho generators are a much larger change to
> the language than two new special methods with unusual arguments.)

I don't think generators are that large a change.  Pre-generators I
wrote a lot of code which looked like this

class TwoLineIterator:
    def __init__(self, infile):
      self.infile = infile
      self._n = 0
    def next(self):
      line = self.infile.readline()
      if not line:
        return None
      self._n = self._n + 1
      return [line, self.infile.readline()]
    def __getitem__(self, i):
      if self._n != i:
        raise TypeError("forward iteration only!")
      x = self.next()
      if x is None:
          raise IndexError(i)
      return x

I got so I could crank out the code almost without thinking.

With iterators, I added

    def __iter__(self):
        return iter(self, None)

With generators I changed the whole thing to

def TwoLineIterator(infile):
    while 1:
        line = infile.readline()
        if not line:
          break
        yield [line, infile.readline()]

Externally, the interface is exactly the same

for data in TwoLineIterator(open("input.txt")):
    ...

Conceptionally then, I see yield (on top of the iterator protocol)
as a great way to simplify building an existing idiom.  And
in addition, it lets me turn highly stateful operations (like a
tree or graph traversal) into iterators.  When the element
generation is several loops deep, it's even harder.  Without
generators, I ended up using threads to get the iterator-like
feel I wanted.

But Python the language did let me get that feel, even in the
1.4 days, and adding generators to Python has not affected
that feel.

Consider though the "two new special methods with
unusual arguments."  Assume the details of getting the stack
frames, etc have been worked out, along with problems of
not knowing the __and__ method even exists until the code
is run.  (It could be added after the class is created.)

You're left with functions which behave different from any
other function, and where the behaviour cannot be used
anywhere else.

First, they behave different.  What's the object passed to
the function?  It's callable, it contains some execution stack
information, to get the locals.  It's a pretty complicated
thing.  Does that data type already exist?  Although I don't
know the internals that well, I don't think so, which means
it needs to be written, documented, available for introspection,
etc.

Can that object be saved?  Eg, what does this do?

class Spam:
    def __and__(self, other):
      self.saved = other
      return other()

spam = Spam()
try:
  a = spam and 1/0:
except ZeroDivisionError:
  pass
spam.saved()

For some languages, like Smalltalk and Ruby, this makes sense.
Those languages support code blocks, which can be passed
around and executed.  But Python does not.

Were Python to have code blocks, then it should be applied
more generally to Python code.  Consider the if/else PEP of
a couple months ago.  With code blocks, the following would
be possible

ifelse(a != 0, 1/a, None)

which would pass the 1/a and None as independent code
blocks, to be executed based on the evaluation of a != 0.

And Guido said that this sort of function would not be one
of the ways to resolve the PEP, which I take to mean that
it's not really a Python solution.

BTW, this would also require some sort of prototyping, to
specify which fields are to be passed as blocks vs. evaluated
before passing, as in

def ifself(cond, if_true is code, if_false is code):
  if cond:
    return if_true()
  return if_false()

but that just doesn't feel right, which I take to mean it
isn't really Python.  It looks like Python, but it doesn't
feel like it.

And that's why I say that code which handles this sort
of special __and__ and __or__ case, if added to Python,
would produce code which wasn't really Python.  It may
be related to Python -- given the feedback I've seen from
people who like code blocks in other languages, I can
understand why people would like them in a Python-like
language.  But it would not be Python.

                    Andrew
                    dalke at dalkescientific.com.






More information about the Python-list mailing list