Is a Python function call an area of ​​bloodletting, a state unable to initialize parameters?

Before I have the courage to write a bug report, I decided to test my assumptions among the smarter Pythonistas. Today I came across an obscure case, so I dropped it to the toy example shown below:

#!/usr/bin/env python # -*- coding: UTF-8 -*- """ A little script to demonstrate that a function won't re-initialize its list parameters between calls, but instead allows them to retain state. """ def bleedscope(a=[], b=[]): """ On each call, unless explicitly passed, both `a` and `b` should be initialized as empty lists. """ c = a if b: c.extend(b) return len(c) x = bleedscope(b=[1]) print x # Should be 1, as expected. x = bleedscope(b=[2]) print x # Expect also to be 1, but it 2. `a` is retained. x = bleedscope(a=[1]) print x # Now 1 as expected. x = bleedscope(b=[3]) print x # 1 as expected? No, it 3! Insanity! 

I thought that the arguments to the function are local in volume to the function and were garbage collected at the end of the function call so as never to save state between them. However, I tested the above script on Python 2.5.2 and Python 2.6.1, and my understanding does not produce results. Argument a certainly preserves the state between most of these calls; the most confusing is the last bleedscope call, where it skips the state of the previous call and returns to the state at the end of the second (ie [1, 2] ). [I suggest running this in my favorite debugger to see for yourself. If you don't have one, I suggest Winpdb as a standalone standalone PSS debugger for FOSS.]

What's going on here?

+4
scope python
Jun 06 '09 at 6:15
source share
4 answers

In Python parameter values, the default value is only initialized when parsing a def call. In the case of an object (for example, your lists), it is reused between calls. Take a look at this article, which also contains the necessary workaround:

http://effbot.org/zone/default-values.htm

+15
Jun 06 '09 at 6:20
source share
— -

It's your problem:

 def bleedscope(a=[], b=[]): 

he should be

 def bleedscope(a=None, b=None): if a is None: a = [] if b is None: b = [] 

The default parameters are executed only once when the function is parsed, thus using the same 2 lists each time.

+8
Jun 06 '09 at 6:21
source share

This is a FAQ .

+4
Jun 07 '09 at 12:06
source share

Oddly enough, your input and your output are very similar, for completely random reasons.

Actually, what happens to Python is that the default values ​​for a and b in your method declaration are "static" values. They are set once when defining a method. That way, your default "a" is pressed every time you don't pass "a" as an argument.

Put "print a" at the beginning of your method to see how this happens.

+1
Jun 06 '09 at 6:33
source share



All Articles