Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python function returns different results when called repeatedly [duplicate]

Tags:

python

When I run the python code below,

def main():
    #print prime_factors(10)
    print prime_factors(9)

def prime_factors(n, i=2, factors=[]):
    if n==1:
        return factors
    if(n%i==0):
        factors.append(i)
        n = n/i
        return prime_factors(n, i, factors)
    else:
        return prime_factors(n, i+1, factors)

if __name__ == '__main__':
    main()

it returns the expected results, it returns the prime factors of 9:

[3, 3]

If I remove the comment from line 2 "print prime_factors(10)", something strange happens. For 10 everything is fine, but for 9 it does not only contain the prime factors of 9, but those of 10, as well:

[2, 5]
[2, 5, 3, 3]

If I call the function with the two optional arguments

def main():
    print prime_factors(10, i=2, factors[])
    print prime_factors(9, i=2, factors[])

everything works fine.

[2,5]
[3,3]

I can't figure out why. I suspect this is some issue with scopes, but I just don't understand it :-( Any help would be appreciated.

like image 883
Stefan Thesing Avatar asked Dec 20 '22 03:12

Stefan Thesing


2 Answers

The default values defined for function arguments are "sticky" - they belong to the function body itself, so when you modify them they stay modified for the next call.

like image 121
Mark Ransom Avatar answered Dec 22 '22 16:12

Mark Ransom


This is because factors is a mutable default argument. A new list called factors is evaluated only once, and hence if you mutate the list, you get the mutated list in the succeeding calls. See the following snippet -

>>> def test(a = []):
        a.append('x')
        return a

>>> test()
['x']
>>> test()
['x', 'x']

Try initializing it's default to None and then checking on None and assigning an empty list within the function body.

>>> def test(a = None):
        if a is None:
            a = []
        a.append('x')
        return a

>>> test()
['x']
>>> test()
['x']
like image 30
Sukrit Kalra Avatar answered Dec 22 '22 16:12

Sukrit Kalra