Python language basics 31: mutable objects as default arguments

Introduction

In the previous post we discussed how to provide optional arguments to a function. We saw how easy it was to assign a default value to a function argument using the assignment operator ‘=’. The caller could optionally ignore those arguments so that the default ones would be used within the function body. Alternatively the caller could override the defaults and provide its own argument values.

In this post we’ll discuss an additional facet of optional function arguments. Optional arguments are evaluated only once along with the function. This can cause unexpected results when mutable objects are passed as default arguments.

Mutable default arguments

Let’s first return to our previous example with 2 default arguments:

def multiply(base, multiplier=2, show_greeting=True):
    if show_greeting:
        print("Welcome to the multiply function")
    return base * multiplier

When the multiply function is executed for the first time then all default arguments are evaluated along with the function and its name. Multiplier will be set to 2 and show_greeting to True. These values are not evaluated upon subsequent function executions.

An implication is that you’ll need to take precautions when using mutable objects as default function arguments. Recall our previous example from this post where we discussed the dangers of object references within functions:

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

Let’s turn this into a modify_list function and have an empty list as an optional input parameter:

def modify_list(list_param=[]):
    list_param.append("Default")
    return list_param

Let’s call this function and let the default value take over:

l1 = modify_list()
print(l1)

This prints…

[‘Default’]

…as expected.

However, let’s call the same function over and over again:

l1 = modify_list()
l1 = modify_list()
l1 = modify_list()
print(l1)

This prints…

[‘Default’, ‘Default’, ‘Default’]

…which is not really what we’ve expected.

What happens is that list_param=[] is evaluated once when modify_list is executed for the first time. It is created as an empty list like it says in the function signature. Then the list gets a single element “Default” and is returned. The second time the function is executed the default argument is not re-evaluated to an empty list. It is already stored in memory as a list which contains a single element “Default” hence it will be used within the function. It gets one more element called “Default”. The happens upon subsequent calls.

A consequence is that you should always try to rely on immutable objects such as strings or numbers for default arguments.

Read the next post of this series here.

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.

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 )

Twitter picture

You are commenting using your Twitter 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: