On 8/6/07, <b class="gmail_sendername">Guido van Rossum</b> <<a href="mailto:guido@python.org">guido@python.org</a>> wrote:<div><span class="gmail_quote"></span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
On 8/3/07, Kurt B. Kaiser <<a href="mailto:kbk@shore.net">kbk@shore.net</a>> wrote:<br>> If the statistics on the usage of map() stay the same, 2/3 of the time<br>> the current implementation will require code like
<br>><br>> foo = list(map(fcn, bar)).<br><br>And the 2to3 tool should make this transformation (unless it can tell<br>from context that it's unnecessary, e.g. in a for-loop, or in a call<br>to list(), tuple() or sorted().
</blockquote><div><br><br>I hate to be pedantic, but it is not possible for 2to3 to tell, in general, that it is safe to elide the list() because the result is used directly in a for loop (for the usual arguments that use the Halting Problem as a trump card).
e.g.,<br><br><span style="font-family: courier new,monospace;"> foo = map(f,seq)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> for i in foo:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> if g(i):</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> break</span><br><br>cannot be correctly transformed to (in Python
2.5 parlance):<br><br><span style="font-family: courier new,monospace;"> foo = imap(f,seq)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
for i in foo:</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> if g(i):</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
break</span><br>
<br>or equivalently:<br><br><span style="font-family: courier new,monospace;">
for x in seq:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> if g(f(x)):</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">
break</span><br>
<br>
when f has side-effects, since:<br> 1. the loop need not evaluate the entire sequence, resulting in f(i) being called for some prefix of seq<br> 2. g(i) may depend on the side-effects of f not yet determined<br><br>Given that Python revels in being a non-pure functional language, we can poke fun of examples like:
<br><br><span style="font-family: courier new,monospace;"> map(db.commit, transactions)</span><br><br>but we need to recognize that the semantics are very specific, like:<br><br><span style="font-family: courier new,monospace;">
map(db.commit_phase2, map(db.commit_phase1, transactions))<br><br></span>that performs all phase 1 commits before any phase 2 commits.<br><br>More so, the former idiom is much more sensible when 'commit' returns a meaningful return value that must be stored. Would we blink too much at:
<br><br><span style="font-family: courier new,monospace;"> results = []</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> for tx in transactions:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> results.append(db.commit(tx))</span><br><br>except to consider rewriting in 'modern' syntax as a list comprehension:<br><br><span style="font-family: courier new,monospace;">
results = [ db.commit(tx) for tx in transactions ]</span><br><br></div></div>I'm all for 2to3 being dumb. Dumb but correct. It should always put list() around all uses of map(), filter(), dict.keys(), etc to maintain the exact behavior from
2.6. Let the author of the code optimize away the extra work if/when they feel comfortable doing so. After all, it is their job/reputation/life on the line, not ours.<br><br>~Kevin<br><br>