Vatsal Parekh

Your friendly web dev

Of assignment and copy in Python

2018-03-12

Assignments in Python bind/rebind values or are used to modify attributes/items of objects.

Lets look at some examples in python repl:

>>> foo = 420
>>> bar = 42
>>> id(foo)
140010894053264
>>> id(bar)
140010929038688

For those who don't know what id is

>>> help(id)

Help on built-in function id in module builtins:

id(obj, /)
    Return the identity of an object.

    This is guaranteed to be unique among simultaneously existing objects.
    (CPython uses the object's memory address.)
>>> id(foo) == id(bar)
False
>>> foo = 42
>>> bar = 420
>>> id(foo)
140010929038688
>>> id(bar)
140010894053264
# So python just gave them address pointing to already existing object
# Make sense since they are just bindings to objects
# Swapping would yeild same result then
>>> foo, bar = bar, foo
>>> id(foo), id(bar)
(140010894053264, 140010929038688)
# Yup
>>>

But things get more interesting when dealing with more complex types than plain old int.

# So lets make a dictionaryt
>>> dictionary = {'foo': 'bar', 'ayy': [43,4324,54]}
>>> dictionary
{'foo': 'bar', 'ayy': [43, 4324, 54]}
# make another dictionaryt from previous one
>>> dictionary2 = dictionary
>>> dictionary2
{'foo': 'bar', 'ayy': [43, 4324, 54]}
# So lets change something in dictionary2
>>> dictionary2['ayy'][1] = 99
>>> dictionary2
{'foo': 'bar', 'ayy': [43, 99, 54]}
# Welp dictionary also got changed along with dictionary2
>>> dictionary
{'foo': 'bar', 'ayy': [43, 99, 54]}
>>> id(dictionary) == id(dictionary2)
True
# Make sense we were operating on the same object
# So while we thought we operated on different object
# It was the same one all along
>>>

But what if we intended to keep the original dictionary for later and do some calculation on dictionary2? You can use copy lib from the standard library.

Its got two functions:

copy.copy(x)

    Return a shallow copy of x.


copy.deepcopy(x)

    Return a deep copy of x.

Straight from the doc page:

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

So deep copy makes a completely new object that you can do henceforth do whatever you want with while keeping a new object

>>> dictionary = {'foo': 'bar', 'ayy': [43, 99, 54]}
>>> from copy import copy, deepcopy
>>> dictionary2 = deepcopy(dictionary)
>>> dictionary2
{'foo': 'bar', 'ayy': [43, 99, 54]}
>>> id(dictionary2) == id(dictionary)
False
>>> dictionary2['foo'] = 12
>>> dictionary2
{'foo': 12, 'ayy': [43, 99, 54]}
>>> dictionary
{'foo': 'bar', 'ayy': [43, 99, 54]}
# So our original dictionary is still intact cool
>>>

But if you wanted to share some objects say dictionary['ayy'] while wanting to do changes to dictionary['foo'] you can make a shallow copy using copy.copy(x)

There are probably few more things you might want to read about copy lib, I recommend reading the docs. RTFM ^^