Python language basics 29: passing the reference value into a function

Introduction

In the previous post we looked at the effects of modifying the value of an object. We saw the difference between mutable and immutable objects. Immutable objects cannot be changed directly in memory whereas mutable objects can. You need to keep in mind that if two object variables reference the same value then changing one variable value will also change the value of all other references.

In this post we’ll discuss what this behaviour means when objects are passed as arguments into functions. Functions will be able to modify the referenced argument which will also affect the object that was originally passed in. If you’re not aware of this behaviour it can cause irritation and buggy code.

Passing objects by reference

Say you have a dictionary object and a function that modifies an incoming dictionary object. Here’s the function:

def modify_dictionary(dictionary):
    dictionary["XL"] = "Extra large"
    return dictionary

Suppose that you want to call the above function and pass in your dictionary object. However, you don’t want to modify the dictionary that was passed into the function. A naive solution could look like this:

myFirstDictionary = {"S": "Small", "M": "Medium", "L": "Large", "XL": "X-Large"}
newDictionary = modify_dictionary(myFirstDictionary)
print(myFirstDictionary)
print(newDictionary)

What do you think the print statements will give you? The following:

{‘L’: ‘Large’, ‘M’: ‘Medium’, ‘XL’: ‘Extra large’, ‘S’: ‘Small’}
{‘L’: ‘Large’, ‘M’: ‘Medium’, ‘XL’: ‘Extra large’, ‘S’: ‘Small’}

The function even modified the original dictionary, i.e. myFirstDictionary. There are cases when this is exactly what you want to achieve.

This is the same behaviour we saw in the previous post:

myFirstDictionary = {"S": "Small", "M": "Medium", "L": "Large", "XL": "X-Large"}
mySecondDictionary = myFirstDictionary
myFirstDictionary["S"] = "Smallish"
myFirstDictionary["XXL"] = "XX-Large"
print(myFirstDictionary)
print(mySecondDictionary)

myFirstDictionary will be passed into the modify_dictionary function by reference. Just like we saw in the previous post Python won’t magically create a copy of myFirstDictionary when the modify_dictionary is called. If you want to make sure that your original object remains intact then it’s your responsibility to ensure that in code.

One solution is to create a so-called deep copy of the object. A deep copy is a copy where we copy every single property of the object so that two variables reference different values even if the values are otherwise identical.

A deep-copy function for a dictionary can look like this:

def deep_copy_dictionary(dictionary):
    deep_copy = {}
    for item in dictionary:
        deep_copy[item] = dictionary[item]
    return deep_copy

There’s nothing special in here. We just copy each key-value pair of the dictionary argument into another dictionary and return the copy. Here’s one way to use the copy function:

myFirstDictionary = {"S": "Small", "M": "Medium", "L": "Large", "XL": "X-Large"}
copy = deep_copy_dictionary(myFirstDictionary)
newDictionary = modify_dictionary(copy)
print(myFirstDictionary)
print(newDictionary)

myFirstDictionary will be left intact:

{‘M’: ‘Medium’, ‘XL’: ‘X-Large’, ‘L’: ‘Large’, ‘S’: ‘Small’}
{‘M’: ‘Medium’, ‘S’: ‘Small’, ‘L’: ‘Large’, ‘XL’: ‘Extra large’}

Read all Python-related posts on this blog here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

4 Responses to Python language basics 29: passing the reference value into a function

  1. ldavid says:

    Nice post. Just a small addendum, if I may: your function deep_copy_dictionary isn’t exactly deep copy, as it will copy the reference of sub-dictionaries (dictionaries inside of the dictionary passed as a parameter), instead of copying all their fields as well.
    You can easily fix this by changing line 4 of deep_copy_dictionary to:

    deep_copy[item] = isinstance(dictionary[item], dict) and deep_copy_dictionary(dictionary[item]) or dictionary[item]
    

    Alternatively (and a more Pythonic way), you could use the implemented copy util:

    import copy
    new_dictionary = copy.deepcopy(dictionary)
    

    Cheers!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: