Last iteration?

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Fri Oct 19 20:15:12 EDT 2007


En Fri, 19 Oct 2007 19:12:49 -0300, Michael J. Fromberger  
<Michael.J.Fromberger at Clothing.Dartmouth.EDU> escribió:

> Before I affront you with implementation details, here's an example:
>
> | from __future__ import with_statement
>
> | with last_of(enumerate(file('/etc/passwd', 'rU'))) as fp:
> |     for pos, line in fp:
> |         if fp.marked():
> |             print "Last line, #%d = %s" % (pos + 1, line.strip())
>
> In short, last_of comprises a trivial context manager that knows how to
> iterate over its input, and can also indicate that certain elements are
> "marked".  In this case, only the last element is marked.

The name is very unfortunate. I'd expect that last_of(something) would  
return its last element, not an iterator.
Even with a different name, I don't like that marked() (a method of the  
iterator) should be related to the current element being iterated.

> We could also make the truth value of the context manager indicate the
> marking, as illustrated here:
>
> | with last_of("alphabet soup") as final:
> |     for c in final:
> |         if final:
> |             print "Last character: %s" % c
>
> This is bit artificial, perhaps, but effective enough.  Of course, there

Again, why should the trueness of final be related to the current element  
being iterated?

> is really no reason you have to use "with," since we don't really care
> what happens when the object goes out of scope:  You could just as
> easily write:
>
> | end = last_of(xrange(25))
> | for x in end:
> |   if end:
> |     print "Last element: %s" % x

Again, why the truth value of "end" is related to the current "x" element?

> But you could also handle nested context, using "with".  Happily, the
> machinery to do all this is both simple and easily generalized to other
> sorts of "marking" tasks.  For example, we could just as well do
> something special with all the elements that are accepted by a predicate
> function, e.g.,
>
> | def isinteger(obj):
> |     return isinstance(obj, (int, long))
>
> | with matching(["a", 1, "b", 2, "c"], isinteger) as m:
> |     for elt in m:
> |         if m.marked():
> |             print '#%s' % elt,
> |         else:
> |             print '(%s)' % elt,
> |
> |     print

I think you are abusing context managers *a*lot*!
Even accepting such evil thing as matching(...), the above code could be  
equally written as:

m = matching(...)
for elt in m:
   ...

Anyway, a simple generator that yields (elt, function(elt)) would be  
enough...

-- 
Gabriel Genellina




More information about the Python-list mailing list