Python optional parameters Python optional parameters python python

Python optional parameters


You need to understand how default values work in order to use them effectively.

Functions are objects. As such, they have attributes. So, if I create this function:

>>> def f(x, y=[]):        y.append(x)        return y

I've created an object. Here are its attributes:

>>> dir(f)['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',   '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__',    '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']

One of them is func_defaults. That sounds promising, what's in there?

>>> f.func_defaults([],)

That's a tuple that contains the function's default values. If a default value is an object, the tuple contains an instance of that object.

This leads to some fairly counterintuitive behavior if you're thinking that f adds an item to a list, returning a list containing only that item if no list is provided:

>>> f(1)[1]>>> f(2)[1, 2]

But if you know that the default value is an object instance that's stored in one of the function's attributes, it's much less counterintuitive:

>>> x = f(3)>>> y = f(4)>>> x == yTrue>>> x[1, 2, 3, 4]>>> x.append(5)>>> f(6)[1, 2, 3, 4, 5, 6]

Knowing this, it's clear that if you want a default value of a function's parameter to be a new list (or any new object), you can't simply stash an instance of the object in func_defaults. You have to create a new one every time the function is called:

>>>def g(x, y=None):       if y==None:           y = []       y.append(x)       return y


you need to do the following:

class A:    def __init__(self, builds=None):        if builds is None:            builds = B()        self.builds = builds

it's a very wide-spread error, using mutable parameters as a default arguments. there are plenty of dupes probably on SO.


Yes; default parameters are evaluated only at the time when the function is defined.

One possible solution would be to have the parameter be a class rather than an instance, a la

def foo(blah, klass = B):    b = klass()    # etc