0

Maybe this is a very easy question to someone, I can't understand what this happened.

I try to solve problems using python generator. However, sometime generator seems not to work that I expected.

The code below is the very simple python generator. It takes integer n and set visited as its arguments. visited should be initialized set() when the function is called.

def simple_gen(n, visited=set()): 
    for i in range(0, n):
        if i not in visited:
            yield i
            visited.update([i])

a = simple_gen(10)
b = simple_gen(10)
print(f"a: {list(a)}")
print(f"b: {list(b)}")

But, when the code is executed, the output is like below. generator a generator value like that I expected, but b doesn't. b doesn't generator any value, it is just empty value.

arguement visited always initialized to empty set as default value. but it doesn't look like initializing.

a: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b: []

I don't understand why this happened. Are there anyone know this, please let me know.

I always thanks for your help.

frhyme
  • 966
  • 1
  • 15
  • 24

1 Answers1

3

Python's default parameters are stored in the function object. This means they're only created once when the function is defined, they are not initialised every time the function is called.

As a result, if you modify a mutable parameter, that modification will remain between calls.

And that's exactly what you're doing here: you have a mutable default parameter, you add stuff to it on the first call, and on the second call visited starts as {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}. That's why you don't normally use mutable default parameters in Python, it's very error prone and somewhat tricky to debug.

Create your visited as a normal local variable, I don't see any reason why it'd even be a parameter.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • Thank for your help. "pythons' default parameter are stored in the function object" is the correct thing I want to know. I really appreciated your help. – frhyme Mar 04 '20 at 07:24
  • 1
    Incidentally, although the way the mapping works is a bit odd, they're stored in `func.__defaults__` and `func.__kwdefaults__` (as the name indicates, the latter is for keyword-only parameters). – Masklinn Mar 04 '20 at 07:30