0

Yesterday, I made a Sieve of Eratosthenes to generate prime numbers and ran into a little weirdness that I can't really figure out.

My original code looked like this:

def generate(n, p=2, primes=[2], composites=set()):
    numbers = [i for i in range(p + 1, n + 1) if i % 2 != 0]
    composites = composites.union({p * i for i in range(p ** 2, n)})
    for i in numbers:
        if i > p and i not in composites:
            primes.append(i)
            return generate(n, i, primes, composites)
    else:
        return primes

But, with successive calls, this happens:

>>> generate(5)
[2, 3, 5]
>>> generate(5)
[2, 3, 5, 3, 5]
>>> generate(5)
[2, 3, 5, 3, 5, 3, 5]
>>> generate(5)
[2, 3, 5, 3, 5, 3, 5, 3, 5]

So it adds [3, 5] every call. It appears that the 'primes' list is in scope after successive calls to the generate function.

I fixed it by passing a copy of the list when the function recurses.

    if i > p and i not in composites:
        return generate(n, i, primes + [i], composites)

Anybody know what is happening here?

1 Answers1

1

Because you pass it through the function argument, the independent scope of each function is pointing to the same data. Mutating one of them mutates it everywhere.

mhlester
  • 22,781
  • 10
  • 52
  • 75