Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python function default parameter is evaluated only once? [duplicate]

People also ask

What is default parameter in Python?

Default values indicate that the function argument will take that value if no argument value is passed during function call. The default value is assigned by using assignment (=) operator.

What is fallback in Python?

In Python, a default parameter is defined with a fallback value as a default argument. Such parameters are optional during a function call. If no argument is provided, the default value is used, and if an argument is provided, it will overwrite the default value.


Python passes parameters to functions by value; So for objects, the value passed is a reference to the object, not a new copy of the object.

That, along with the following part of the official docs is what helped me understand it better (emphasis mine):

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 the 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. [...] A way around this is to use None as the default, and explicitly test for it in the body of the function [...]

Putting it all together:

If you define the default for a parameter to be a mutable object (such as []) then the "pre-computed" value is the reference to that object, so each call to the function will always reference the same object, which can then be mutated across multiple invocations of the function.

However, since None is an immutable built-in type, the "pre-computed" value for a default of None is simply that. So the parameter will be None each time you call the function.

Hopefully that helps! I do think that the tutorial could have had better wording, because I was also confused by that at first.


"The default value is only evaluated once" does not mean that a parameter with a default retains its value between invocations of the function. It means that the expression which you specify (the None part of def f(a, L=None)) is evaluated once, and the object it results in is stored in a hidden location and re-used if no value for that parameter is given at call. Parameters are still reset to the value (default or not) at every invocation.


In your second example you have a variable L. At first L refers to None. You repoint it to a new empty list on each invocation, then mutate that new list. Remember L = [] is the same as L = list()

In your first example, however, L is set to the new list once at function declaration. L isn't reset to [] on each invocation of the function. So you are always mutating the same list.


I think this is happening because a list is a mutable object while the value None is immutable.

For the first function, variable L is outside the function environment (in the function definition), and it refers to an empty list. Then you make changes to this list in the function environment, but since a list is mutable, the variable L that is outside the function environment refers to this now mutated list, and the change propagates each time you call the function.

For the second function, variable L is also outside the function environment (in the function definition), but this time it refers to None, which is immutable. Now, every change you make in the function environment will not affect what L refers to outside the function environment. The variable L inside the function environment refers to something different as you change it. First, it refers to an empty list, and then a list that gets a value appended to it. You then return this list. The next time you call the function, you call it with the variable L that is outside the function environment, which has not changed and still refers to None.

Hope this makes sense.


What happens is as follows:

When a python function is called, it is evaluated in the environment in which it was defined and not the environment in which it was called although the second part is secondary ( no pun intended) for the purpose of answering your question.

The default arguments are evaluated only once at the time of function definition. This creates a closure. Think of closure as function code + environment in which the function was been defined.

So in this case when the function was defined, L was assigned to [] and now every subsequent call to the function will use this value of L.

The tutorial also mentions:

The default values are evaluated at the point of function definition in the defining scope (and the defining scope is part of the closure along with function code)

http://docs.python.org/2/tutorial/controlflow.html#default-argument-values