[Tutor] Issues with initializing lists
Tom Jenkins
tjenkins@devis.com
Fri, 10 Aug 2001 13:33:38 -0400
Hello,
Yep this one bites _everyone_ at some point. Lets take a look...
Leona Euler wrote:
> Hi,
>
> As an example:
>
>>>>l1=[[None]*3]*4
>>>>l1
>>>>
> [[None, None, None], [None, None, None], [None, None, None], [None, None,
> None]]
What is happening here is that 4 copies of the _same_ list are being
generated. We can confirm this in the interpreter:
>>> l1 = [[None]*3]*4
>>> print l1
[[None, None, None], [None, None, None], [None, None, None], [None,
None, None]]
>>> for sub in l1:
... print id(sub)
...
17189420
17189420
17189420
17189420
>>>
Note the print id(sub) call... lets see what the docs say:
>>> id.__doc__
"id(object) -> integer\n\nReturn the identity of an object. This is
guaranteed to be unique among\nsimultaneously existing objects. (Hint:
it's the object's memory address.)"
>>>
Ok so we see that they all point to the same memory location.
[snip]
>
> I could do
>
> l1=[]
>
>>>>for i in range(4):
>>>>
> ... l1.append([])
> ... for j in range(3):
> ... l1[i].append(None)
> ...
> l1[1][1]='hello'
>
>>>>l1
>>>>
> [[None, None, None], [None, 'hello', None], [None, None, None], [None, None,
> None]]
>
Lets look at this one in the interpreter:
>>> l2 = []
>>> for i in range(4):
... l2.append([])
... for j in range(3):
... l2[i].append(None)
...
>>> print l2
[[None, None, None], [None, None, None], [None, None, None], [None,
None, None]]
>>> for sub in l2:
... print id(sub)
...
15857188
15854956
15852996
15858828
>>>
Ok different numbers, so different memory locations, so different objects.
So now we know _why_ it was working / not working in the previous two
algorithms.
> This looks fine. But this approach really seems excessive.
>
Lets see if we can tighten this up.
>>> l3 = []
>>> for i in range(4):
... l3.append([None]*3)
...
>>> print l3
[[None, None, None], [None, None, None], [None, None, None], [None,
None, None]]
>>> for sub in l3:
... print id(sub)
...
17236724
15244756
17238524
17238444
>>>
ok, cool that one is shorter and gives us different ids.
Now lets see if there is another way. Basically anytime you see a
simple loop like above, you should be able to replace it with a list
comprehension (on python 2 and above). So lets try that...
>>> l4 = [[None]*3 for x in range(4)]
>>> print l4
[[None, None, None], [None, None, None], [None, None, None], [None,
None, None]]
>>> for sub in l4:
... print id(sub)
...
17182676
17182004
17182380
17236980
>>>
>>> l4[1][1] = 'hello'
>>> print l4
[[None, None, None], [None, 'hello', None], [None, None, None], [None,
None, None]]
>>>
Viola!
--
Tom Jenkins
devIS - Development Infostructure
http://www.devis.com