initialising a list of lists

Steven D'Aprano steve at REMOVETHIScyber.com.au
Wed Nov 16 16:18:08 EST 2005


On Wed, 16 Nov 2005 13:58:45 +0100, Peter Kleiweg wrote:

> 
> This does not what I want it to do:
> 
>     >>> a = [[]] * 6
>     >>> a[3].append('X')
>     >>> a
>     [['X'], ['X'], ['X'], ['X'], ['X'], ['X']]
> 
> This does what I want:
> 
>     >>> b = [[] for _ in range(6)]
>     >>> b[3].append('X')
>     >>> b
>     [[], [], [], ['X'], [], []]
> 
> The first is clear and wrong. 

That is correct. It is wrong because you make six references to the same
empty list instead of six different empty lists.

> The second is hairy and right.

I disagree. I think the second method is just as clear as the first.

> Is there a way to do it clear and right?

There are lots of ways to do it right. Clarity is in the eye of the
beholder. But perhaps the clearest way is the most explicit:

>>> c = []
>>> for i in range(6):
...    c.append([])
>>> c[3].append('X')
>>> c
[[], [], [], ['X'], [], []]


I can't help feeling though that this is such a common task, and so often
trips up newbies, that it deserves a built in list method. I base my
reasoning on the existence of methods like extend:

Instead of writing:

for item in seq:
    L.append(item)

the Powers That Be created L.extend(seq). This isn't the only case of very
simple idioms being made even shorter in Python.

So perhaps there should be a list method that takes an integer argument
and appends that many empty lists:

d = []
d.append_empties(5)

Or even a function that does this:

def nested(numcopies, base=None, *args):
    if base is None:
        base = []
    for i in range(numcopies):
        base.append(args[:])
    return base





-- 
Steven.




More information about the Python-list mailing list