-3
def fib1(n, cache = {}):
    if n <= 1:
        return 1
    if n not in cache:
        cache[n] = fib1(n-1) + fib1(n-2)
    return cache[n]


def fib2(n, cache = {}):
    if n <= 1:
        return 1
    if n not in cache:
        cache[n] = fib2(n-1, cache) + fib2(n-2, cache)
    return cache[n]

Why does fib1 still work when I don't pass in cache as a parameter like I do in the second function fib2?

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • I think SO has multiple topics about "mutable default arguments". – gog Apr 17 '14 at 19:00
  • As you don't pass an argument with the keyword `cache` it uses the default value (in this case your dictionary). That's why both functions work the same way because it is automatically using the same dictionary. – Ffisegydd Apr 17 '14 at 19:03
  • What happens if you replace "cache = {}" with "cache = dict()"? – Scott Hunter Apr 17 '14 at 19:03

1 Answers1

1

To elaborate on my comment above...

In the first version, cache is initialized once with an empty dict, and subsequent function calls access this single dict and modify it.

In the second version, you pass the cache dict around, but it's still one and the same dict.

In both versions, there's only one cache dict in the whole program. Even if you call the function 100 times, this will be a single one. The mutable default arguments are "sticky" like that and most of the time are bad idea.

gog
  • 10,367
  • 2
  • 24
  • 38
  • @PadraicCunningham: exactly. A MDA (=mutable def arg) is like a function's attribute. You set it once and then modify without passing it explicitly. – gog Apr 17 '14 at 19:11
  • @PadraicCunningham: yes, if it's `None` you have no means to modify it and you have to pass it around. – gog Apr 17 '14 at 19:36