I've stumbled onto a python behavior that I don't understand at all.
Python 2.5.2 (r252:60911, Jul 31 2008, 17:28:52)
# function
def X(l=[]):
l.append(1)
print l
# first call of X
X()
[1]
#second call of X
X()
[1, 1]
Where does the list parameter 'l' live between the two successive calls of X().
Why is it not recreated with an empty list?
Is this correct behavior or is it a Python bug?
Does anyone have any pointers to the language documentation where this behavior is described?
Thanks all
Bart van Deenen
http://docs.python.org/ref/function.html
"Default parameter values are evaluated when the function definition
is executed."
Depending on your use the common way to handle this is to do
def x(lst = None):
if lst is None:
pass # lst has not been set to anything
else:
pass # lst has been set to something
> I've stumbled onto a python behavior that I don't understand at all.
...
> Does anyone have any pointers to the language documentation where this behavior is described?
Yes, it's documented in FAQ:
http://www.python.org/doc/faq/general/
Question 4.22.
--
Regards,
Wojtek Walczak,
http://tosh.pl/gminick/
Thanks all for your answers. I figured your solution already, but now I understand where the behavior is from. One question remains: can I find my parameter 'l' somewhere? I looked in a lot of objects, but couldn't find it.
Thanks
Bart.
cokof...@gmail.com wrote:
> On Aug 22, 11:13 am, Bart van Deenen
> <b...@at.vandeenensupport.punt.com.invalid> wrote:
>>
>> # function
>> def X(l=[]):
>> l.append(1)
>> print l
>>
>> # first call of X
>> X()
>> [1]
>>
>> #second call of X
>> X()
>> [1, 1]
>>
>> Where does the list parameter 'l' live between the two successive calls
>> of X(). Why is it not recreated with an empty list?
>> Is this correct behavior or is it a Python bug?
>> Does anyone have any pointers to the language documentation where this
>> behavior is described?
>>
It's amazing. I didn't analyse this properly, but IMHO this issue is the
single most asked question (or rather the effects in produces) on this list.
Maybe we should get *really* explicit in
http://docs.python.org/tut/node6.html#SECTION006710000000000000000
and
http://docs.python.org/ref/function.html
Big, red warnings, or some such.
Diez
def foo(x="default value for x"):
pass
print foo.func_defaults
=> ('default value for x',)
> Thanks all for your answers. I figured your solution already, but now I understand where the behavior is from. One question remains: can I find my parameter 'l' somewhere? I looked in a lot of objects, but couldn't find it.
YOURFUNCTION.func_globals['YOURFUNCTION'].func_defaults
> It's amazing. I didn't analyse this properly, but IMHO this issue is the
> single most asked question (or rather the effects in produces) on this list.
>
> Maybe we should get *really* explicit in
>
> http://docs.python.org/tut/node6.html#SECTION006710000000000000000
>
> and
>
> http://docs.python.org/ref/function.html
>
> Big, red warnings, or some such.
+1
Documenting this should also make it easier to understand
the difference between mutable/immutable objects before one
comes on c.l.py and asks about it.
> It's amazing. I didn't analyse this properly, but IMHO this issue is the
> single most asked question (or rather the effects in produces) on this
> list.
I feel a bit dumb to ask a FAQ on the newsgroup. The problem with this particular question is that I found it hard to find a query that would give meaningful answers.
Thanks for your patience all.
Bart
Bart van Deenen wrote:
> I feel a bit dumb to ask a FAQ on the newsgroup. The problem with
> this particular question is that I found it hard to find a query that
> would give meaningful answers.
See my new thread "How to search the Python manuals".
tjr
> I've stumbled onto a python behavior that I don't understand at all.
http://effbot.org/zone/default-values.htm
> Is this correct behavior or is it a Python bug?
Python's been out there for nearly 20 years. I think you safely can
assume that if this really was a bug, someone else would have found it
by now.
</F>
I happen to be reading about decorators at the moment:
from copy import deepcopy
def nodefault(myfunc):
myfunc_defaults = myfunc.func_defaults
def fresh(*args, **kwargs):
myfunc.func_defaults = deepcopy(myfunc_defaults)
return myfunc(*args, **kwargs)
return fresh
@nodefault
def X(l=[]):
l.append(1)
print l
>>> for i in range(1,6):
... X()
...
[1]
[1]
[1]
[1]
[1]
Which is just a very fancy way of doing:
def X(l=[]):
if l is None:
l = []
l.append(1)
print l
* sound of two pennies *