4

I'm not quite sure how to phrase it yet, so I'll demonstrate what I mean.

a = 1
b = 2
my_list = [a,b]
print my_list # [1,2]

a = a + 1
b = b * 2
print a # 2
print b # 4

# prints [1,2] but I want [2,4]
print my_list

This happens for tuples and sets too. What is the data structure I need? Or what is the logic I need?

FriskySaga
  • 409
  • 1
  • 8
  • 19

1 Answers1

6

Integers are immutable. That means that once you've created an integer object, e.g. with a = 1, it can never be changed. That doesn't mean that you can't rebind the name a to another object, just that the value of the integer object itself won't change.

When you do a = a + 1, you are creating a new integer with value 2, and assigning it to a. But the original 1 is still around. In fact the element my_list[0] still refers to the original object, since it was never told to refer to anything else. In that sense, names are like pointers in Python.

To get the list element to change, you have two options:

  1. Tell it to change explicitly. Any time you modify a, set my_list[0] = a again. Or just drop a entirely. Why have two references to the same object of you don't need to? You can do

    my_list[0] += 1
    my_list[1] *= 2
    
  2. Store a mutable object in the list. Strings and integers, as you already saw, are immutable. Tuples are as well. But sets, dicts and lists are mutable, so any in-place changes you make to them will be directly visible. This is probably not the best option in your particular case, but here's an example:

    a = [1]
    b = {2}
    my_list = [a, b]
    a[0] += 1
    a.append(3)
    b.add(4)
    print my_list
    

    [[2, 3], {2, 4}]
    

Both of methods shown here work just fine for lists. The notation for sets is a little different for sets since in the first case, you'd have to remove the original object and insert the new one. The concept is the same though.

Only the second method could work with tuples though, and even that's not usually recommended. As I mentioned earlier, tuples are supposed to be immutable. The are certain expectations that come with that, like hashability, which are violated when you put a mutable object, like a list, into a tuple. It's perfectly fine to do that, but you just have to be a little careful.

For your particular use-case (accessing the values by name, but also grouping them into a single data structure), dictionaries may be more suitable than lists. You can index a dictionary much like a list, except that the keys can be the names you want instead of essentially arbitrary indices. Your example would look like this:

my_dict = {
   'a': 1,
   'b': 2,
}

my_dict['a'] += 1
my_dict['b'] *= 2

print my_dict

<p/>

{'a': 2, 'b': 4}
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Thank you for the detailed answer. I sent this question to a coworker, and he suggested for me to use dictionaries instead, so I might do that. – FriskySaga Feb 12 '19 at 14:27
  • 1
    @FridaySky. I've added a note at the end – Mad Physicist Feb 12 '19 at 14:57
  • Thanks for adding the extra note, but when I return my_dict.values(), it doesn't come out in the expected order. Currently trying to figure a workaround. – FriskySaga Feb 12 '19 at 17:40
  • 1
    @Friday. Dictionaries aren't sorted in Python 2. You can look up how to get the right order on SO. It's been asked many times. – Mad Physicist Feb 12 '19 at 17:55
  • Figured it out. It took me a while because I didn't find this link until now: https://stackoverflow.com/questions/25480089/right-way-to-initialize-an-ordereddict-using-its-constructor-such-that-it-retain I had been doing it the first way and couldn't get my dictionary to maintain order. – FriskySaga Feb 12 '19 at 18:40