List of lists surprising behaviour

Lie Ryan lie.1296 at gmail.com
Thu Jun 17 21:38:59 EDT 2010


On 06/18/10 09:20, bart.c wrote:
> 
> "J Kenneth King" <james at agentultra.com> wrote in message
> news:87wrtxh0dq.fsf at agentultra.com...
>> candide <candide at free.invalid> writes:
>>
>>> Let's the following code :
>>>
>>>>>> t=[[0]*2]*3
>>>>>> t
>>> [[0, 0], [0, 0], [0, 0]]
>>>>>> t[0][0]=1
>>>>>> t
>>> [[1, 0], [1, 0], [1, 0]]
>>>
>>> Rather surprising, isn't it ?
>>
>> Not at all, actually.
> 
> The code is clearly trying to set only t[0][0] to 1, not t[1][0] and
> t[2][0]
> as well.
> 
> This behaviour is quite scary actually, especially when t[0]=42 *does* work
> as expected, while t[0][0]=42 is apparently duplicated. It appears
> inconsistent.

I agree, the behavior is often quite inconvenient, but I disagree that
it is inconsistent. List multiplication behavior is consistent with the
tenet: "objects are never copied unless explicitly requested"

Peeking further:
t = [[0] * 2] * 3
print id(t[0]) == id(t[1])  # True
print id(t[0][0]) == id(t[1][0])  # True

so, it is consistent (though it is quite inconvenient).

>> I'd be surprised if the multiplication operator was aware of object
>> constructors.  Even arrays are "objects" in Python.  Should the
>> multiplication operator know how to instantiate three arrays from a
>> single array instance?  What about an instance of a user-defined class?
> 
> Multiplication operators shouldn't need to be directly aware of any such
> thing; it should just request that an object be duplicated without
> worrying about how it's done.
> 
> I don't know how Python does things, but an object should either specify
> a special way of duplicating itself, or lend itself to some standard way
> of doing so. (So for a list, it's just a question of copying the data in
> the list, then recursively duplicating each new element..)

That is inconsistent with the tenet. Moreover, the implicit copying
makes it quite difficult to reason about the program's behavior. How
would you propose this list should be copied:

class O(object):
    def __init__(self):
        self.attr = 0
    def add(self):
        self.attr += 1

b = [[O()] * 2] * 3



More information about the Python-list mailing list