2.3 list reverse() bug?

Alex Martelli aleaxit at yahoo.com
Mon Dec 29 08:05:08 EST 2003


On Sunday 28 December 2003 11:56 pm, Andrew MacIntyre wrote:
> > Apparently, these miniscule extra bits of overhead appear to be enough
> > for Andrew to reject the "essentially equivalent" evaluation.
>
> You have misconstrued the intent of my observation, which was simply to
> highlight that there may be a reason other than aesthetics to choose one
> of the 3 alternatives.

There can be several such reasons, and the performance differences among the 
various constructs, which you singled out as the only thing worth mentioning, 
are hardly ever interesting enough to reject the "essentially equivalent" 
tag.  To me, the most interesting issues arise in circumstances where 
_polymorphism_ is in play -- in other words, where you want to code a 
function so that it works with other types of sequences (or other iterables) 
as arguments, _not_ just Python lists.  Under such circumstances, list(x) 
does ensure the type of its result (a list), whatever the type of x, as long 
as x is iterable.  copy.copy(x) should instead return an object of the same
type as x -- each of these two behaviours may be preferable, depending
on other circumstances.  x[:] on the other hand guarantees just about
nothing -- in particular, it does not guarantee that a shallow copy is taken,
as it might well return a sequence that shares data with x (that's what it
does for Numeric arrays, a crucial sequence type for many applications
of Python).

If you're thinking of a programmer choosing among the various copy idioms,
in each and every case that presents itself, on the basis of a full grounds-up
analysis of all the considerations that apply to that specific case, then 
there is no reason, except aesthetics, to prefer one idiom over the others
"in general".  One may _recode_ a copy originally coded as list(x) into x[:],
for example, as an optimization under very special circumstances (i.e. after
ascertaning that the operation is a bottleneck and that it often occurs on
tiny enough lists to matter) -- but of course it would be suboptimal to
prematurely _prefer_ x[:] as a matter of course given that the performance
differences often won't matter (you know what they say about premature
optimization, yes?).  The _functional_ advantages of list(x) and copy.copy(x)
will matter only when the type of x is not entirely certain -- for example 
when one wants, as a rule, to write reusable code (optimizing it, at the
expense of reducing reusability, only if and when performance increase is
_demonstrably_ necessary)... but some people believe that "premature
generality" (including reusability) is almost as bad a trap as premature
optimization (MHO is that in theory it _might_ be, but in practice the latter
tends to be a far worse blight).

I believe, however, that much coding happens to "just use the idiom one
is most familiar with" for a given functionality -- rather than on the basis 
of a specific, detailed, exhaustive analysis, with each line of code one 
writes, of all the functional, robustness, and performance requirements
that apply to that exact set of circumstances.  Because of this perfectly
natural occurrence, I further believe that it's important to _acquire good
idiomatic coding habits_ -- such good habits maximize the probability that
the code we write "by rote, without deep specific analysis" will be good
enough.  Very rarely will the "goodness" of roughly equivalent idioms be
determined by performance issue, in my opinion; basically, almost only
cases where different idioms yield different big-O performance, as in the
notorious performance pitfall of "bigstring += smallstring" loops versus
''.join(sequence_of_smallstrings).  One exception might be the use of
somelist.sort(comparison) versus DSU idioms -- they both have the same
big-O performance characteristics, but the multiplicative constants can be
SO much bigger, when passing a comparison function, that some care is
warranted in order to make DSU a habit.

Much more often than by performance considerations, the choice of
what idiom is a "good habit" to acquire may be guided by issues of
generality, robustness, functionality.  In this light, I think that list(x) is
generally preferable to x[:], and more often than not slightly better
than copy.copy(x), as the habitual way to code for this functionality --
not, IMHO, a "premature generalization", because it _is_ essentially
equivalent to the alternatives... but, when the difference matters, it
tends to favour it more often than not (on axes other than ones which
relate directly to optimization).


Alex






More information about the Python-list mailing list