Many newbie questions regarding python

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Oct 9 02:20:06 EDT 2010


On Thu, 07 Oct 2010 18:34:58 -0700, alex23 wrote:

> On Oct 8, 10:27 am, Steven D'Aprano <st... at REMOVE-THIS-
> cybersource.com.au> wrote:
>> >     v = [0 for i in range(20)]
>>
>> Absolutely not. Such a code snippet is very common, in fact I've done
>> it myself, but it is a "hammer solution" -- to a small boy with a
>> hammer, everything looks like a nail that needs hammering. Writing such
>> a list comprehension is a "list comp solution".
>>
>> >     v = [0] * 20
>>
>> Yes, this is the solution.
> 
> But the list comp version will work as expected for mutable types,
> whereas the 'solution' only works for immutable types.

Yes, that is a good point. Repeating the same mutable object may give 
surprising results.


> If anything, I feel like the list comp version is the correct solution
> because of its reliability, whereas the multiplication form feels like
> either a lucky naive approach or relies on the reader to know the type
> of the initialising value and its mutability.

And how often do you have an list that you are creating where you don't 
know what items you have to initialise the list with?

There are three common use-cases for the idiom the OP was describing: 
initialising a list with zeroes (or sometimes some other numeric value), 
initialising it with None, or creating a list-of-lists (or more rarely, a 
list-of-dicts). The first one is *far* more common than the next two.

You are right to point out that the third case is a Python gotcha: [[]]*n 
doesn't behave as expected by the naive or inexperienced Python 
programmer. I should have mentioned it, and pointed out that in that case 
you do want a list comp [[] for i in range(n)].

But that doesn't mean that the list comp is the general purpose solution. 
Consider the obvious use of the idiom:

def func(arg, count):
    # Initialise the list.
    L = [arg for i in range(count)]
    # Do something with it.
    process(L, some_function)

def process(L, f):
    # Do something with each element.
    for item in enumerate(L):
        f(item)


Looks good, right? But it isn't, because it will suffer the exact same 
surprising behaviour if f modifies the items in place. Using a list comp 
doesn't save you if you don't know what the object is.



-- 
Steven



More information about the Python-list mailing list