Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
329 views
in Technique[技术] by (71.8m points)

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

a = b = c = 1

After 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:

a += 1

a 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.


For 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:

name = something

The 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:

a = "foo"  # `a` is the name of the string "foo" 
b = {"bar": a}  # evaluate the new dictionary and name it `b`.  `a` is looked up and returns "foo" in this calculation
a = "bar"  # give the object "bar" the name `a` irrespecitve of what previously had that name

1I'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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...