which methods to use?
Florian Leitner
fleitner at REMcnioOVE.es
Thu Mar 29 06:14:26 EDT 2007
* Alex Martelli wrote, On 3/29/07 9:46 AM:
> <s99999999s2003 at yahoo.com> wrote:
>> another query, in the docs, list(a) and a[:] does the same thing (a =
>> [1,2,3] for example), but besides the speed of slicing is faster than
>> list(), what advantage is there for using list(a) in this case ?
>
> Readability (a word is more readable than idiomatic punctuation), and
> conceptual uniformity with making shallow copies of other containers of
> known types such as sets and dicts.
I just want to summarizes what Alex is saying (correct me if I'm
wrong!): usually, you do not want to use copy.copy, and copy.deepcopy
only when you really need it (which is, if I search for it in my
library, very seldom). As to whether use list(lst), [x for x in lst],
list(x for x in lst), or just lst[:], I'd summarize it to this:
list(lst):
most expressive; use if you want to explicitly create a copy of a list
and only a list or if you want to ensure that whatever sequence you
received gets transformed to a list.
[list comprehension] and gen(erators):
usually to create a copy of a list, generator function or sequence with
some modification; using list comprehension always creates list, with a
generator setup you could do (for example):
tup = tuple(x + 1 for x in int_lst)
Some people also argue generators are faster, but I'd advise you to use
what is more understandable first - you are asking what methods are
faster, but keep in mind: "premature [code] optimization is the root of
all evil", or so... (from T. Hoare/D. Knuth). And believe me, this
statement holds always, as I had to learn the bloody hard way!
using slices[:]:
preserves the sequence you are using, so you could create a function
that accepts list, tuples, strings or any other sequence as input and
makes a copy of the sequence regardless of its type and returns that
type. A very nice example of this is can be found in the
Permutations/Combinations/Selections recipe from the Python Cookbook (R
19.15):
def _combinators(_handle, items, n):
# factored-out common structure for:
# combinations, selections and permutations
if n == 0:
yield items[:0]
return
for i in range(len(items)):
this_one = items[i:i + 1]
for cc in _combinators(_handle, _handle(items, i), n - 1):
yield this_one + cc
def combinations(items, n):
""" take n distinct items, order matters """
def skipIthItem(items, i):
return items[:i] + items[i+1:]
return _combinators(skipIthItem, items, n)
def uniqueCombinations(items, n):
""" take n distinct items, order is irrelevant """
def afterIthItem(items, i):
return items[i+1:]
return _combinators(afterIthItem, items, n)
def selections(items, n):
""" take n (not necessarily distinct) items, order matters """
def keepAllItems(items, i):
return items
return _combinators(keepAllItems, items, n)
def permutations(items):
""" take all items, order matters """
return combinations(items, len(items))
Because _combinators() returns "yield items[:0]" (i.e. the empty input
sequence) instead of, say, an empty list ("yield list()"), and because
the assignment to this_one in _combinators() is not "this_one =
[items[i]]", but "this_one = items[i:i+1]", you can use any sequence as
input to these functions, not just lists. Yet, it arguably might not be
the most efficient solution because of the recurring sequence
concatenations in the inner functions and the yield statement...
-Florian
More information about the Python-list
mailing list