0

I have a list of 10,000 tuples. Each tuple has 31 entries. Let's say I just want to modify only the first entry of the 77th tuple.

empty_tuple=[0] * 31
lst=[empty_tuple] * 10000
lst[77][0]='salut'

It does work but all the first entries of all the 10,000 tuples are now the same. What's going on here?

print lst[1987][0]
'salut'
hans glick
  • 2,431
  • 4
  • 25
  • 40
  • 3
    It looks like you're creating lists, not tuples. Tuples are immutable, you can't modify them. You are creating a copy of the *same* object in every list element. Modifying it modifies all copies. You need a deep copy. [Check out this tutorial.](http://www.python-course.eu/deep_copy.php) – Bob Dylan Jan 11 '16 at 16:34
  • 5
    Your `lst` contains 10,000 references to the same list. Try with `lst = [empty_tuple[:] for _ in range(10000)]` – Andrea Corbellini Jan 11 '16 at 16:36
  • Yeah sorry it's a list of lists – hans glick Jan 11 '16 at 17:01
  • Ok Thank you Andrea. Why is there a '_' in lst = [empty_tuple[:] for _ in range(10000)] ? Is it a typo? – hans glick Jan 11 '16 at 17:05
  • @hansglick: `_` is conventionally the name for unused variables – Andrea Corbellini Jan 11 '16 at 17:08
  • Possible duplicate of [Python list of lists, changes reflected across sublists unexpectedly](http://stackoverflow.com/questions/240178/python-list-of-lists-changes-reflected-across-sublists-unexpectedly) – TessellatingHeckler Jan 11 '16 at 17:11

1 Answers1

1

[empty_tuple] * 10000 creates a list that contains 10000 references to empty_tuple, so when you modify it with lst[77][0]=..., it will be reflected across all of l.

It's a bit tricky if you really want to use tuples, as they are immutable, but you can do something like:

>>> sett = lambda t, idx, val: tuple((v if i != idx else val) for i,v in enumerate(t))
>>> l = [(0,) * 3] * 4
>>> l
[(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]
>>> l[1] = sett(l[1], 2, 42)
>>> l
[(0, 0, 0), (0, 0, 42), (0, 0, 0), (0, 0, 0)]

where sett is a function that takes a tuple t, an index idx, and a value val, and returns a tuple that is identical to t in every index but idx, where it contains val.

One way to set up a list of distinct lists would be:

>>> l = map(lambda _: [0] * 3, xrange(4))
>>> l[0][1] = 2
>>> l
[[0, 2, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
Vlad
  • 18,195
  • 4
  • 41
  • 71