Puzzling: local variable in recursive function made global?

Peter Otten __peter__ at web.de
Thu Mar 26 15:32:29 EDT 2009


Daniel Oberski wrote:

> Hi Peter,
> 
>> Plus, it works as expected (read: modifies the argument) if you
>> explicitly pass an empty list to the function...
> 
> That is not so. The reason is given by Andrew Cooke in this thread.
> 
> I would "expect" that when function calls lower in the recursion
> hierarchy return, the object is not changed from the point of view of the
> higher-order calls. This is expectation is mistaken because it is "the
> same frickin object" as Andrew said. One thing that goes wrong for
> example is the last unit test given in the program.
> 
> This will happen even if an empty list is explicitly passed in the
> initial call...


As someone who knows Python I would expect that a function like


>>> def append(item, items=None):
...     if items is None:
...             items = []
...     items.append(item)
...     return items
...

always modifies the list argument:

>>> a = []
>>> append("x", a)
['x']
>>> a # a is modified
['x']
>>> b = ["x"]
>>> append("x", b)
['x', 'x']
>>> b # b is modified
['x', 'x']

I would be surprised by the behaviour of Andrew's variant:

>>> def append(item, items=None):
...     items = items or []
...     items.append(item)
...     return items
...
>>> a = []
>>> append("x", a)
['x']
>>> a # a is left alone
[]
>>> b = ["x"]
>>> append("x", b)
['x', 'x']
>>> b # but b is not
['x', 'x']

This is why I prefer a test for the None sentinel over the boolean test.

Peter



More information about the Python-list mailing list