2

I was reading this today: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#default-parameter-values and I can't seem to understand what's happening under the hood.

def bad_append(new_item, a_list=[]):
    a_list.append(new_item)
    return a_list

The problem here is that the default value of a_list, an empty list, is evaluated at function definition time. So every time you call the function, you get the same default value. Try it several times:

I guess first of all, when is the function definition stage? Is it an initialization stage just before the actual main function executes?

My original thinking was that the name a_list gets discarded right after the function runs so whatever [] mutated to will be garbage collected. Now, I think that a_list is not discarded at all since it's only a name bound to the object [] so it never gets garbage collected because a_list is still bound to it. But then again, I'm wondering how I still get the same default value instead of a new []. Can someone straighten this out for me?

Thanks!

1 Answer 1

3

when is the function definition stage?

Look at "Function definitions" in the Python reference:

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that that same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function, e.g.:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

The parameters are evaluated when the function definition is executed. If this is in a module, it happens when the module is imported. If it's in a class, it's when the class definition runs. If it's in a function, it happens when the function executes. Remember that a Python module is evaluated from top to bottom, and doesn't automatically have an explicit "main function" like some languages.

For example, if you put the function definition inside a function, you get a new copy of the function each time:

>>> def make_function():
...     def f(value=[]):
...             value.append('hello')
...             return value
...     return f
... 
>>> f1 = make_function()
>>> f2 = make_function()
>>> f1()
['hello']
>>> f1()
['hello', 'hello']
>>> f2()
['hello']

The function definition creates a new function object, assigns it various properties including the code, formal parameters, and default values, and stores it in a name in the scope. Typically this only happens once for any given function, but there are cases where a function's definition can be executed again.

My original thinking was that the name a_list gets discarded right after the function runs so whatever [] mutated to will be garbage collected.

Inside the body of the function, the name a_list is available to the code. So the name, and the value it is pointing to, must both still be available. It is stored in the func_defaults attribute of the function.

But then again, I'm wondering how I still get the same default value instead of a new [].

Because the [] is evaluated only when the function is defined, not when it is called, and the name a_list points to the same object even across repeated calls. Again, if you want the alternative behavior, use something immutable like None and check for it.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.