Wednesday, December 24, 2025

Mutable Default Elective Arguments · Ponderings of an Andy


The Drawback

With out operating this in your IDE, what does the next code output? Forgive the usage of vins, I work within the logistics subject and cope with automobile identification numbers continuously.

def add_vin(this_vin: str, vins: listing = []):
    if this_vin not in vins:
        vins.append(this_vin)
    return vins

add_vin("VIN1")
add_vin("VIN2")
print(add_vin("VIN3"))

You in all probability noticed that vins is an elective argument and that it defaults to an empty listing. Run this perform thrice with out passing it an inventory to append to, and it is affordable to imagine that you’ve got a closing results of an inventory with a single merchandise contained in it – VIN3

Sadly, that is unsuitable. The output is definitely ["VIN1", "VIN2", "VIN3"]

Why?

What is going on on?

In Python, default arguments are certain to a perform on the time the perform is outlined. That is solely accomplished as soon as. If you happen to do not go the elective argument in to the perform name, the identical listing is modified when the perform known as. Because of this within the instance above, a brand new listing is just not created every time the perform known as with out the elective vins argument.

We are able to see this by barely modifying the code above to indicate the item ID we’re working on.

def add_vin(this_vin, vins=[]):
    if this_vin not in vins:
        print(f"id={id(vins)}")    # Print the item ID we're appending to
        vins.append(this_vin)
    return vins

Which outputs the next because it provides every VIN.

id=2954990867712
id=2954990867712
id=2954990867712
['VIN1', 'VIN2', 'VIN3']

Every time add_vin was known as with out passing it an inventory to function on, the perform will function on the identical default listing.

One other instance

The instance above is fundamental, however will get the purpose throughout. Nonetheless, let us take a look at one thing a bit extra frequent. Connecting to a database with a connection object on the parameter.

def open_database(connection = make_connection(host='instance.com')):
    # do database issues with `connection`
    connection.shut()

Properly accomplished. You have closed your connection. Your DBA will thanks. Nonetheless, what occurs subsequent time you name open_database() in your code? In any case, your connection data is there by default, you need not go a brand new connection, proper?

Once more, unsuitable. You have closed the connection and it is the default argument. The following name to open_database will make the most of the identical connection object. A connection that’s closed. Your database name will fail.

Final Instance

One final instance:

import datetime, time

def print_datetime(dt = datetime.datetime.now()):
    return str(dt)

print(print_datetime())
time.sleep(10)
print(print_datetime())

That is going to print the present datetime, sleep for 10 seconds, and print the brand new datetime – proper?!

No.

2023-10-06 08:45:21.392973
2023-10-06 08:45:21.392973

Why?!

Once more, an elective default argument is just certain as soon as. Since a brand new worth is not handed to the perform on the second name, the very same worth is used the second time by means of. Whoops.

What can I do about this?

The most suitable choice, in my view, is to set the default values to None. That is going to make it very apparent that there’s a downside. Within the first instance, you may get an exception as a result of you possibly can’t append to None. Within the second, your database calls will error as a result of None would not include connection data. Within the third, you may print None as an alternative of an anticipated datatime.

You would go an immutable object like a tuple or a frozenset, however even these have caveats to concentrate on. For instance, a tuple can include one thing mutable in it (ie. an inventory). Personally, I favor to make the most of None.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles