Multi-dimensional list initialization

Andrew Robinson andrew3 at r3dsolutions.com
Tue Nov 6 06:51:24 CET 2012


On 11/05/2012 06:30 PM, Oscar Benjamin wrote:
> On 6 November 2012 02:01, Chris Angelico<rosuav at gmail.com>  wrote:
>> On Tue, Nov 6, 2012 at 12:32 PM, Oscar Benjamin
>> <oscar.j.benjamin at gmail.com>  wrote:
>>> I was just thinking to myself that it would be a hard thing to change
>>> because the list would need to know how to instantiate copies of all
>>> the different types of the elements in the list. Then I realised it
>>> doesn't. It is simply a case of how the list multiplication operator
>>> is implemented and whether it chooses to use a reference to the same
>>> list or make a copy of that list. Since all of this is implemented
>>> within the same list type it is a relatively easy change to make
>>> (ignoring backward compatibility concerns).
>>>
>>> I don't see this non-copying list multiplication behaviour as
>>> contradictory but has anyone ever actually found a use for it?
>> Stupid example of why it can't copy:
>>
>> bad = [open("test_file")] * 4
>>
>> How do you clone something that isn't Plain Old Data? Ultimately,
>> that's where the problem comes from. It's easy enough to clone
>> something that's all scalars (strings, integers, None, etc) and
>> non-recursive lists/dicts of scalars, but anything more complicated
>> than that is rather harder.
> That's not what I meant. But now you've made me realise that I was
> wrong about what I did mean. In the case of
>
>     stuff = [[obj] * n] * m
>
> I thought that the multiplication of the inner list ([obj] * n) by m
> could create a new list of lists using copies. On closer inspection I
> see that the list being multiplied is in fact [[obj] * n] and that
> this list can only know that it is a list of lists by inspecting its
> element(s) which makes things more complicated.
>
> I retract my claim that this change would be easy to implement.
>
>
> Oscar
Hi Oscar,

In general, people don't use element multiplication (that I have *ever* 
seen) to make lists where all elements of the outer most list point to 
the same sub-*list* by reference.  The most common use of the 
multiplication is to fill an array with a constant, or short list of 
constants;  Hence, almost everyone has  to work around the issue as the 
initial poster did by using a much longer construction.

The most compact notation in programming really ought to reflect the 
most *commonly* desired operation.  Otherwise, we're really just making 
people do extra typing for no reason.

Further, list comprehensions take quite a bit longer to run than low 
level copies; by a factor of roughly 10. SO, it really would be worth 
implementing the underlying logic -- even if it wasn't super easy.

I really don't think doing a shallow copy of lists would break anyone's 
program.
The non-list elements, whatever they are, can be left as reference 
copies -- but any element which is a list ought to be shallow copied.  
The behavior observed in the opening post where modifying one element of 
a sub-list, modifies all elements of all sub-lists is never desired as 
far as I have ever witnessed.

The underlying implementation of Python can check an object type 
trivially, and the only routine needed is a shallow list copy.  So, no 
it really isn't a complicated operation to do shallow copies of lists.

:)



More information about the Python-list mailing list