Optional Arguments in Python March 7, 2008

Optional arguments in python are obviously very useful allowing you to have default values so you don’t need to pass them every time. A simple hello world example always goes a long way…

def hello(to="world"):
    print "Hello,", to
>>> hello("Steve")
Hello, Steve
>>> hello()
Hello, world

Sometimes you’ll see people define an optional argument with a default value of None then override it in the function’s body. This might seem a strange thing to do at first, but there is a reason. Let’s say that we wanted to be able to say hello to a list of people and for it to automatically add “World” to the list.

def hello(to=[]):
    to.append("World")
    if len(to) > 1:
        greeting = "Hello, " + ", ".join(to[:-1]) + " and " + to[-1]
    else:
        greeting = "Hello, " + to[0]
print greeting
>>> hello(["Steve", "Matt"])
Hello, Steve, Matt and World
>>> hello(["Steve", "Matt"])
Hello, Steve, Matt and World
>>> hello()
Hello, World
>>> hello()
Hello, World and World
>>> hello()
Hello, World, World and World

This happens because the value for the default argument is the same list every time, so when we modify it the function has the same modified list as the default argument when it is subsequently called. This is probably not the behaviour you would expect and you would rarely want to use this behaviour. The way around it is to define the default argument as None then override it.

def hello(to=None):
    if to is None:
        to = []
    to.append("World")
    if len(to) > 1:
        greeting = "Hello, " + ", ".join(to[:-1]) + " and " + to[-1]
    else:
        greeting = "Hello, " + to[0]
    print greeting

>>> hello()
Hello, World
>>> hello()
Hello, World
>>> hello(["Steve", "Matt"])
Hello, Steve, Matt and World
>>> hello(["Steve", "Matt"])
Hello, Steve, Matt and World

By setting to to [] at run time the list is a new list each time the function is run. Previously the list was created when the function was defined, meaning the same list was appended to.