[Tutor] Question on lists

David Ascher da@ski.org
Thu, 18 Mar 1999 13:23:56 -0800 (Pacific Standard Time)


On Thu, 18 Mar 1999, Martijn Faassen wrote:

> Here's the improved function:
> 
> from math import floor, sqrt
> 
> def factor(n, a = []):        # if no second argument is passed, use the
>     k = floor(sqrt(n))
>     for i in range(2, k+1):
>         if n%i == 0:
>             a.append(i)       # more efficient and readable than a.insert(len(a), i)
>             factor(n/i, a)    # Factor quotient
>             break
>     return a
> 
> print factor(36) # test things

Martijn should know better than to use an empty list as a default argument
-- he was probably not awake when he wrote that.  Try calling factor(36) a
few times and look at the results:

>>> factor(36)
[2, 2, 3]
>>> factor(36)
[2, 2, 3, 2, 2, 3]
>>> factor(36)
[2, 2, 3, 2, 2, 3, 2, 2, 3]
>>> factor(36)
[2, 2, 3, 2, 2, 3, 2, 2, 3, 2, 2, 3]

That's because of the famous 'mutable default argument problem', discussed
in the FAQ Question 6.25 http://www.python.org/doc/FAQ.html#6.25.

The solution is to use None and do a test in the body of the function:

def factor(n, a = None):        
    if a is None: a = []
    k = floor(sqrt(n))
    for i in range(2, k+1):
        if n%i == 0:
            a.append(i)       
            factor(n/i, a)    
            break
    return a

>>> factor(36)
[2, 2, 3]
>>> factor(36)
[2, 2, 3]
>>> factor(36)
[2, 2, 3]
>>> factor(36)
[2, 2, 3]

Note that the code *still* doesn't work (it's missing a 3), but I'll leave
that one to others. =)

--david