Python bug with [] as default value in functions?

Chris Gonnerman chris.gonnerman at usa.net
Thu Apr 12 09:00:25 EDT 2001


----- Original Message -----
From: "Dinu Gherman" <gherman at darwin.in-berlin.de>
Subject: Python bug with [] as default value in functions?


> Hi,
>
> I noticed a very strange behaviour: I've got a recursive func-
> tion like this:
>
>   foo(spam, eggs=[]):
>     ...
>     return foo(spam, eggs=eggs)
>     # the following is the same:
>     # return foo(spam, eggs)

The problem is deceptively simple:  The list given in the function
definition is the SAME LIST each time you call the function.  If you
are familiar with C, think "static variable" and you'll get what I
mean.

The list contains the results of the first top-level call when the
second top-level call is made (instead of being empty).

> where the default argument for eggs, the empty list, is *empty*
> for the top-level call *only* when it is explicitly provided
> with the function call like this:
>
>   bar = foo(mySpam, eggs=[])
>
> I've attached a longer example showing, I hope, rather pre-
> cisely what I mean.
>
> Is this a bug (I'm using Win2K, Py 2.0) or just a lack of un-
> derstanding of recursion and name spaces, delicate as they
> are, in my brain (which is not entirely excluded today...)??
>
> Regards,
>
> Dinu
>
> --
> Dinu C. Gherman
> ReportLab Consultant - http://www.reportlab.com
> .................................................................
> "The only possible values [for quality] are 'excellent' and 'in-
> sanely excellent', depending on whether lives are at stake or
> not. Otherwise you don't enjoy your work, you don't work well,
> and the project goes down the drain."
>                     (Kent Beck, "Extreme Programming Explained")


----------------------------------------------------------------------------
----


> """
> A test script indicating that empty lists as default values
> for function arguments might not work as they should.
>
> The default value [] is not used as defined in the function
> signature, except when the function is called indicating this
> very value explicitely.
>
> The functions used compute recursively a list of integers
> with a sum less than or equal to some given maximum value.
>
> Found on Python 2.0/Win2K.
>
> Dinu Gherman
> """
>
> from operator import add
>
>
> # [] as default value for L does not seem to work properly!!!
>
> def maxNumList1(Max, L=[]):
>     """Find list of consecutive numbers n_i, where sum(n_i) < Max.
>
>     This function computes recursively a list of ordered integers
>     n_i, i = 0...m, starting at n_0 = 0, with n_i+1 = n_i + 1
>     and sum(n_i) <= Max.
>
>     E.g.
>       maxNumList1(0) = [0]
>       maxNumList1(1) = [0, 1]
>       ..
>       maxNumList1(4) = [0, 1, 2]
>       ..
>       maxNumList1(6) = [0, 1, 2, 3]
>       ..
>       maxNumList1(9) = [0, 1, 2, 3]
>       maxNumList1(10)= [0, 1, 2, 3, 4]
>       ..
>     """
>
>     assert Max >= 0, "Maximum must be a positive integer."
>
>     # Add initial 0 or next integer.
>     if L == []:
>         L.append(0)
>     else:
>         L.append(L[-1]+1)
>
>     # Return list if maximum exceeded or recurse.
>     if reduce(add, L) > Max:
>         return L[:-1]
>     else:
>         return maxNumList1(Max, L=L)
>
>
> def maxNumList2(Max, L=None):
>     "Same as maxNumList1, but uses None as default value."
>
>     # Hack to fix the bug.
>     if L == None:
>         L = []
>
>     # From here on identical to maxNumList1() - except for
>     # the call to itself at the bottom.
>
>     assert Max >= 0, "Maximum must be a positive integer."
>
>     # Add initial 0 or next integer.
>     if L == []:
>         L.append(0)
>     else:
>         L.append(L[-1]+1)
>
>     # Return list if maximum exceeded or recurse.
>     if reduce(add, L) > Max:
>         return L[:-1]
>     else:
>         return maxNumList2(Max, L=L)
>
>
> # This is only for reference purposes and does not matter
> # or affect the strange behaviour of the implementation
> # of maxNumList1().
> def maxNumList3(Max):
>     "Behaves as maxNumList2, but uses no recursion."
>
>     list = []
>     i = 0
>     while reduce(add, list, 0) <= Max:
>         list.append(i)
>         i = i + 1
>     return list[:-1]
>
>
> def test():
>     print """Testing...
>     The second and third lines should show the same results.
>     The first should show identical results to the second,
>     but doesn't... Bug or no bug??
>     """
>     for i in range(11):
>         n = i
>         print "maxNumList1(%d)       = %s" % (n, maxNumList1(n))
>         print "maxNumList1(%d, L=[]) = %s" % (n, maxNumList1(n, L=[]))
>         print "maxNumList2(%d)       = %s" % (n, maxNumList2(n))
> ##        print "maxNumList3(%d)       = %s" % (n, maxNumList3(n))
>         print
>
>
> if __name__ == "__main__":
>     print __doc__
>     test()
>






More information about the Python-list mailing list