Default function arguments behaving badly

J

jonny.longrigg

Hi

I'm having some trouble with a function I've written in Python:

def myFunction(l1,l2,result=[]):
index=0
for i in l1:
result.append([])
if type(i)==list:
myFunction(i,l2,result[index])
else:
for j in l2:
result[index].append(i*j)
index+=1
return result

l1 and l2 are lists and the function multiplies every element of l1
with every element of l2. l1 is (possibly) multi-dimensional, and the
recursive bit is in there to cope with that. For example, if
l1=[[1,2],[3,4]] and l2=[5,6] the result is
[[[5,6],[10,12]],[[15,18],[20,40]]].

The problem is that it works if I run it once, but then on repeated
runs the value for 'result' doesn't seem to set itself to my default of
[], but instead uses the state it was in last time the function was
run.

I've had a problem like this in the past and ended up rewriting the
function as a class and using something like self.result, but I don't
really like this solution as the code becomes considerabley more
difficult to read (and I suspect less efficient). Also, I suppose I
could feed in an empty array every time but that doesn't provide a very
intuitive interface to the function.

Does anyone know what is going on here? Is there an easy solution?

Thanks for your help!
 
R

rafi

Hi
hi

I'm having some trouble with a function I've written in Python:

def myFunction(l1,l2,result=[]):
index=0
for i in l1:
result.append([])
if type(i)==list:
myFunction(i,l2,result[index])
else:
for j in l2:
result[index].append(i*j)
index+=1
return result
The problem is that it works if I run it once, but then on repeated
runs the value for 'result' doesn't seem to set itself to my default of
[], but instead uses the state it was in last time the function was
run.
Does anyone know what is going on here? Is there an easy solution?

the list you provide as default parameter is evaluated once (at loading
time of the function). so each time you call the function, it uses the
same list that has been filled before... you do not have the problem
with say and int or a string as they are non mutable objects. however
lists are mutable objects so... modify your function as follow:

def myFunction(l1,l2,result=None):
if result is None:
result = []

hth
 
P

Paul McNett

I'm having some trouble with a function I've written in Python:
def myFunction(l1,l2,result=[]):
[snipped rest of function and explanation of what it does]
Does anyone know what is going on here? Is there an easy solution?

It shined out like a supernova. It has to do with mutability of certain
Python objects (e.g. dicts and lists) and the fact that Python binds the
default arguments only once. So, when your function is defined, python
binds the name "result" to the value []. Then, your function runs the
first time using that original binding. The second time, it still uses
the original binding which, because lists are mutable, still contains
the prior list. Etcetera.

The solution is to never assign mutable objects to default arguments.
Instead, assign to None, like:

def myFunction(l1, l2, result=None):
if result is None:
result = []

Others will certainly post links to the python docs that explain this.
 
J

jonny.longrigg

That works perfectly - Thanks! I'm always getting tripped up by the
mutability of lists, I should really learn to look out for it more...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top