int
, float
, str
and tuple
are immutable data types. On the other hand, types like list
and dict
are mutable. This chapter will discuss what happens when you pass a variable to a function or when you assign them to another value/variable.
id
The id() built-in function returns the identity (reference) of an object. Here's some examples to show what happens when you assign a variable to another value/variable.
>>> num1 = 5 >>> id(num1) 140204812958128 # here, num1 gets a new identity >>> num1 = 10 >>> id(num1) 140204812958288 # num2 will have the same reference as num1 >>> num2 = num1 >>> id(num2) 140204812958288 # num2 gets a new reference, num1 won't be affected >>> num2 = 4 >>> id(num2) 140204812958096 >>> num1 10
Pass by reference
Variables in Python store references to an object, not their values. When you pass a list
object to a function, you are passing the reference to this object. Since list
is mutable, any in-place changes made to this object within the function will also be reflected in the original variable that was passed to the function. Here's an example:
>>> def rotate(ip): ... ip.insert(0, ip.pop()) ... >>> nums = [321, 1, 1, 0, 5.3, 2] >>> rotate(nums) >>> nums [2, 321, 1, 1, 0, 5.3]
This is true even for slices of a sequence containing mutable objects. Also, as shown in the example below, tuple
doesn't prevent mutable elements from being changed.
>>> nums_2d = ([1, 3, 2, 10], [1.2, -0.2, 0, 2], [100, 200]) >>> last_two = nums_2d[-2:] >>> last_two[0][-1] = 'apple' >>> last_two[1][-1] = 'ball' >>> last_two ([1.2, -0.2, 0, 'apple'], [100, 'ball']) >>> nums_2d ([1, 3, 2, 10], [1.2, -0.2, 0, 'apple'], [100, 'ball'])
As an exercise, use id()
function to verify that the identity of last two elements of nums_2d
variable in the above example is the same as the identity of both the elements of last_two
variable.
Slicing notation copy
If you wish to copy whole/part of a list
object such that changing the copy version doesn't affect the original list
, the solution will depend on the presence of mutable elements.
Here's an example where all the elements are immutable. In this case, using slice notation is safe for copying.
>>> items = [3, 'apple', 100.23, 'fig'] >>> items_copy = items[:] >>> id(items) 140204765864256 >>> id(items_copy) 140204765771968 # the individual elements will still have the same reference >>> id(items[0]) == id(items_copy[0]) True >>> items_copy[0] += 1000 >>> items_copy [1003, 'apple', 100.23, 'fig'] >>> items [3, 'apple', 100.23, 'fig']
On the other hand, if the list
has mutable objects, using slice notation won't stop the copy from modifying the original.
>>> nums_2d = [[1, 3, 2, 10], [1.2, -0.2, 0, 2], [100, 200]] >>> nums_2d_copy = nums_2d[:] >>> nums_2d_copy[0][0] = 'oops' >>> nums_2d_copy [['oops', 3, 2, 10], [1.2, -0.2, 0, 2], [100, 200]] >>> nums_2d [['oops', 3, 2, 10], [1.2, -0.2, 0, 2], [100, 200]]
copy.deepcopy
The copy built-in module has a deepcopy()
method if you wish to recursively create new copy of all the elements of a mutable object.
>>> import copy >>> nums_2d = [[1, 3, 2, 10], [1.2, -0.2, 0, 2], [100, 200]] >>> nums_2d_deepcopy = copy.deepcopy(nums_2d) >>> nums_2d_deepcopy[0][0] = 'yay' >>> nums_2d_deepcopy [['yay', 3, 2, 10], [1.2, -0.2, 0, 2], [100, 200]] >>> nums_2d [[1, 3, 2, 10], [1.2, -0.2, 0, 2], [100, 200]]
As an exercise, create a deepcopy of only the first two elements of nums_2d
object from the above example.
Top comments (0)