Do you need help?

Notice Board

Per partecipare al corso di Fondamenti di programmazione 2021-22 loggatevi e attivatelo nella vostra pagina dei corsi preferiti. A quel punto il corso appare nel menù personale cliccando sul proprio avatar. Per i materiali degli anni precedenti seguite lo stesso metodo.

To join the Programming/Lab 2021-22 course, log-on and select it on the my courses page. It will appear on the personal menu of your avatar. For earlier years use the same method.



Default argument in recursive functions

benjamin (2490 points)
0 6 21
in Programming in Python by (2.5k points)
edited by

While doing some exercise to prepare for the exam I found myself multiple times with the same "bug" ( allow me the term). Whenever I define a recursive function with some default parameters if I do not specify in the function call those default arguments everything goes wild ( wrong output for some of the tests) .

For example I define the recursive function foo like:

def foo(path,dic ={}, level =1) :

And I call it with :


It doesn't work, while if I call in the following way :

foo(path, {}, 1)

It works fine.

I am really curious to understand why this happens.

Thank for any answer in advance!!!!

PS when I talk about the call I mean not in the recursive function itself but when I call it from the "main"

1 Answer

Silktrader (2550 points)
1 6 16
by (2.6k points)

This (somewhat unexpected) behaviour is peculiar to Python and can be put to good use.

Default arguments are evaluated once when functions are first instantiated; future function calls won't trigger new instances of default arguments.

In your case, the same dictionary will be reused every time you omit the "dic" argument and rely on the default one. Even though the default "dic" dictionary will be empty at the start of the first call, its elements could change during execution and the next function call would operate on the "mutated" default not empty dictionary.

This possible issue doesn't come up when one uses immutable default arguments. Sometimes, to avoid issues with mutable default arguments, I use this pattern:

def foo(path, dic=None, level=1) :
  dic = dic or {}

... which is similar to the safer (no coercion):

if dic is None:
  dic = {}