Congruence of 'map' and 'for' broken in 2.1??

Tim Peters tim.one at home.com
Sat Apr 28 03:37:26 EDT 2001


[nanotech at europa.com]
> ...
> Say I want to sum the integers in a file where there exists one int
> per line:
>
>   >>> fh=open(filename)
>   >>> sum=0
>   >>> for line in fh.xreadlines():
>           sum += int(line)
>   >>> print sum
>   >>> fh.close()
>
> Right? Now the Python Reference Manual explictly states:
>   http://www.python.org/doc/2.1/ref/for.html
>
>   The expression list is evaluated once; it should yield a sequence.
>
> Now by this, the for ought to break, but I can live with the fudging
> going on here

The fudging is real but not where you think <wink>:  the problem is that many
protocols/interfaces in Python exist only in folklore, and "being a sequence"
is one of them.  *Sometimes* "a sequence" means only "supports __getitem__",
but in other contexts it means "plus also supports __len__", and/or "plus
also supports slicing", and in the case of "for" loops also means "raises
IndexError eventually".  If you think that's fuzzy, wait until you bump into
"file-like objects" <wink>.  It's amazing to me that we don't trip over this
stuff more than we do, but in fact we rarely even stumble in practice.

>   ....BUT....
>
> Say I want to do the same thing in the nice simple example given in
> the documentation concerning reduce:
>
>   >>> fh=open(filename)
>   >>> print reduce(lambda x, y: x+y, map(int,fh.xreadlines()))
>   Traceback (most recent call last):
>     File "<pyshell#91>", line 1, in ?
>       print reduce(lambda x, y: x+y, map(int,fh.xreadlines()))
>   TypeError: argument 2 to map() must be a sequence object
>
>
> Ack!! Why will map not fudge? What am I missing?? Is it pilot error??

It's not your fault.  I think it's a buglet in Python's implementation of
map():  internally, map() insists that *its* notion of sequence support both
__getitem__ and __len__.  It uses the latter only to get *guess* an initial
size for the result list, but makes no *essential* use of the lengths (and,
e.g., it doesn't *believe* what len() returns anyway:  just like the
for-loop, map continues iterating until IndexError gets raised, regardless of
whether that's equal to, before or after the # of elements len() said to
expect).

Python 2.2 will be introducing iterator objects, and things like map() have
to get reworked to use iterators anyway.  The problem you're seeing will go
away by magic then.  In the meantime, I think I'll check in a small patch to
make your xreadlines glitch go away in a 2.1 bugfix release.

sequence-is-only-a-sequence-of-8-letters-ly y'rs  - tim





More information about the Python-list mailing list