4

From the Summerfield's Programming in Python3:

it says as follows: when default values are given, they are created at the time the def statement is executed, not when the function is called. But my question is for the following example:

def append_if_even(x, lst =None):
    lst = [] if lst is None else lst
    if x % 2 ==0:
        lst.append(x)
    return lst

As the first time definition executed, lst is point to None But after the function call append_if_even(2),

  • Shouldn't lst point to [2], since after lst.append(x) lst not point to None anymore ?

  • Why the next execution still make lst point to none?

  • What really happen inside this function call append_if_even(2)?
will Liu
  • 43
  • 1
  • 1
  • 6
  • the parameters `x` and `lst` are **not** globals. So setting them has *no impact* on a second call. – Willem Van Onsem Apr 06 '17 at 12:40
  • is that after the function created , it would create a memory space for this function's default argument. When the default argument is needed this local lst would be assigned to the created space with value None ? Is that how default argument work in python? – will Liu Apr 06 '17 at 12:54
  • @wllLiu: well there is only one `None`. But say you have specified `lst = []`. It will construct one list. If you do not specify a `lst`, the `lst` will refer to that list. Otherwise to the given argument. But *setting* the parameter itself has no impact. – Willem Van Onsem Apr 06 '17 at 12:55

1 Answers1

5

Shouldn't lst point to [2], since after lst.append(x) lst not point to None anymore? Why the next execution still make lst point to none?

That is exactly what you prevent by using the lst=None, lst = [] if lst is None else lst construction. While the default arguments for the function are evaluated only once at compile time, the code within the function is evaluated each time the function is executed. So each time you execute the function without passing a value for lst, it will start with the default value of None and then immediately be replaced by a new empty list when the first line of the function is executed.

If you instead were to define the function like this:

def append_if_even(x, lst=[]):
    if x % 2 ==0:
        lst.append(x)
    return lst

Then it would act as you describe. The default value for lst will be the same list (initially empty) for every run of the function, and each even number passed to the function will be added to one growing list.

For more information, see "Least Astonishment" and the Mutable Default Argument.

glibdud
  • 7,550
  • 4
  • 27
  • 37