← Back to team overview

ubuntu-phone team mailing list archive

Autopilot test authors, be aware of a subtle Python issue

 

A quick note about something I've seen a few times in several autopilot tests
as I'm porting them to Python 3.  The issue isn't Python 3 specific though.

Please do not use mutable objects in default arguments!

There is a subtle bug in this function.  Without looking ahead can you guess
what it is?

def foo(spec={}):
    print('spec:', spec)
    if not spec:
        spec['a'] = 7

Here's a hint: Python parses default arguments when the function is defined,
not when it's run.

The bug is that every invocation of foo() gets the same dictionary object, not
a new one.  So subsequent runs of foo() see the mutated dict, e.g.

% python3 -i /tmp/foo.py
>>> foo()
spec: {}
>>> foo()
spec: {'a': 7}


Here's a better way that doesn't exhibit this bug:


def bar(spec=None):
    if spec is None:
        spec = {}
    print('spec:', spec)
    if not spec:
        spec['a'] = 7


>>> bar()
spec: {}
>>> bar()
spec: {}
>>>

The same holds true for using lists as default argument values.  Tuples and
other immutable types are okay of course.

That's it!

Your friendly neighborhood snake wrangler,
-Barry