assigning value in python dict (copy vs reference)
NickName:darkryder Ask DateTime:2014-05-25T13:56:02

assigning value in python dict (copy vs reference)

I understand that in python every thing, be it a number, string, dict or anything is an object. The variable name simply points to the object in the memory. Now according to this question,

>> a_dict = b_dict = c_dict = {}

This creates an empty dictionary and all the variables point to this dict object. So, changing any one would be reflected in the other variables.

>> a_dict["key"] = "value" #say
>> print a_dict
>> print b_dict
>> print c_dict

would give

{'key': value}
{'key': value}
{'key': value}

I had understood the concept of variables pointing to objects, so this seems fair enough.

Now even though it might be weird, since its such a basic statement, why does this happen ?

>> a = b = c = 1
>> a += 1
>> print a, b, c
2, 1, 1   # and not 2, 2, 2

First part of question: Why isn't the same concept applied here ?

Actually this doubt came up when I was trying to search for a solution for this:

>> a_dict = {}
>> some_var = "old_value"
>> a_dict['key'] = some_var
>> some_var = "new_value"
>> print a_dict
{'key': 'old_value'}  # and not {'key': 'new_value'}

This seemed counter-intuitive since I had always assumed that I am telling the dictionary to hold the variable, and changing the object that the variable was pointing to would obviously reflect in the dictionary. But this seems to me as if the value is being copied, not referenced. This was the second thing I didn't understand.

Moving on, i tried something else

>> class some_class(object):
..    def __init__(self):
..        self.var = "old_value"
>> some_object = some_class()
>> a_dict = {}
>> a_dict['key'] = some_object
>> some_object.var = "new_value"
>> print a_dict['key'].var
"new_value"    # even though this was what i wanted and expected, it conflicts with the output in the previous code

Now, over here, obviously it was being referenced. These contradictions has left me squacking at the unpredictable nature of python, even though I still love it, owing to the fact I don't know any other language well enough :p . Even though I'd always imagined that assignments lead to reference of the object, however these 2 cases are conflicting. So this is my final doubt . I understand that it might be one those python gotcha's . Please educate me.

Copyright Notice:Content Author:「darkryder」,Reproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/23852480/assigning-value-in-python-dict-copy-vs-reference

Answers
mgilson 2014-05-25T06:10:21

You're wrestling with 2 different things here. The first is the idea of mutability vs. immutability. In python, str, int, tuple are some of the builtin immutable types compared to list, dict (and others) which are mutable types. immutable objects are ones which cannot be changed once they are created. So, in your example:\n\na = b = c = 1\n\n\nAfter that line, all a, b and c refer to the same integer in memory (you can check by printing their respecitve id's and noting that they are the same). However, when you do:\n\na += 1\n\n\na now refers to a new (different) integer at a different memory location. Note that as a convention, += should return a new instance of something if the type is immutable. If the type is mutable, it should change the object in place and return it. I explain some of the more gory detail in this answer.\n\n\n\nFor the second part, you're trying to figure out how python's identifiers work. The way that I think of it is this... when you write a statement:\n\nname = something\n\n\nThe right hand side is evaluated into some object (an integer, string, ...). That object is then given the name on the left hand side1. When a name is on the right hand side, the corresponding object is automatically \"looked up\" and substituted for the name in the calculation. Note that in this framework, assignment doesn't care if anything had that name before -- it simply overwrites the old value with the new one. Objects which were previously constructed using that name don't see any changes -- either. They've already been created -- keeping references to the objects themselves, not the names. So:\n\na = \"foo\" # `a` is the name of the string \"foo\" \nb = {\"bar\": a} # evaluate the new dictionary and name it `b`. `a` is looked up and returns \"foo\" in this calculation\na = \"bar\" # give the object \"bar\" the name `a` irrespecitve of what previously had that name\n\n\n1I'm glossing over a few details here for simplicity -- e.g. what happens when you assign to a list element: lst[idx] = some_value * some_other_value.",


More about “assigning value in python dict (copy vs reference)” related questions

assigning value in python dict (copy vs reference)

I understand that in python every thing, be it a number, string, dict or anything is an object. The variable name simply points to the object in the memory. Now according to this question, >>

Show Detail

Python assigning string format return value behavior is inconsistent

When assigning a python string format return value like '67.67.%s.%s' % (str(j), str(i)), it is inconsistent between assigning to a key of a dict and assigning to a key in a sub-dict of a dict. For

Show Detail

Python and Django - assigning fields in dict instead of overwriting?

I'm using a Python dict to map strings to Django fields. I want to update, or assign the value of the fields as so. self.sheet_headers_2_fields = { 'Index': self.index, 'Device Model': self...

Show Detail

In Python 2, how to copy list of complex nested elements by value, not reference, regardless of the list's content

I come across some great questions and answers about copying lists by reference vs by value (this, this and this). Unfortunately, none of proposed solutions removes the reference from all the nested

Show Detail

Large dict RAM efficiency, re-assignment vs. update()

I have a large dict of dicts which effectively has the following format: my_dict = { 'A' : { 'B' : { 'C' : { 'key': 'value' }}}} The nest of A,

Show Detail

Deep copy of a dict in python

I would like to make a deep copy of a dict in python. Unfortunately the .deepcopy() method doesn't exist for the dict. How do I do that? >>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]} &gt...

Show Detail

Deep copy of a dict in python

I would like to make a deep copy of a dict in python. Unfortunately the .deepcopy() method doesn't exist for the dict. How do I do that? >>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]} &gt...

Show Detail

Deep copy of a dict in python

I would like to make a deep copy of a dict in python. Unfortunately the .deepcopy() method doesn't exist for the dict. How do I do that? >>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]} &gt...

Show Detail

Deep copy of a dict in python

I would like to make a deep copy of a dict in python. Unfortunately the .deepcopy() method doesn't exist for the dict. How do I do that? >>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]} &gt...

Show Detail

Cython: How do I know when I’m assigning a reference to an object or assigning a copy of an object with the same value?

In Python, I may have: for k, v in mydict: l = v l.set_to_one() print(l._one) for k, v in mydict: print(v._one) and this should print a series of ones (where _one is an integer). W...

Show Detail