Re: initializing with empty list as default causes freaky problems
Quoting Reckoner : > Hi, > > Observe the following: > > In [202]: class Foo(): >.: def __init__(self,h=[]): >.: self.h=h [...] > In [207]: f.h.append(10) > > In [208]: f.h > Out[208]: [10] > > In [209]: g.h > Out[209]: [10] > > The question is: why is g.h updated when I append to f.h? Shouldn't > g.h stay []? What you are seeing is basically the same that happens here: === In [1]: def f(l=[]): ...: l.append(1) ...: print l ...: In [2]: f() [1] In [3]: f() [1, 1] In [4]: f() [1, 1, 1] === The problem is that the default value "[]" is evaluated only once, at function creation time, and not at invocation. Thus, every call to the function shares the same default object. That is consistent with python's function type: the "def" construct just creates a function object and initializes it with the code, argument list and default values. That means that the default value are part of the function object itself, regardless of when/if it is called: === In [5]: f.func_defaults Out[5]: ([1, 1, 1],) === The recommended way of dealing with this case (mutable default arguments) is: def f(l = None): if l is None: l = [] # the code goes here. (in your case, your g.__init__ and f.__init__ methods share the same Foo.__init__ function, and thus, share the same default value []) That is a very common python gotcha, and I think it is well documented in the standard doc (but I can't find it right now, sorry). Unfortunately, it doesn't become intuitive until you've spent a while understanding python's execution model (and then you suddenly realize that it just makes sense). [And now I wonder... how other languages do it? I've spent so much time with python that reevaluating the default argument on invocation feels clumsy, but I'm obviously tainted now...] Regards, -- Luis Zarrabeitia Facultad de Matemática y Computación, UH http://profesores.matcom.uh.cu/~kyrie -- Participe en Universidad 2010, del 8 al 12 de febrero de 2010 La Habana, Cuba http://www.universidad2010.cu -- http://mail.python.org/mailman/listinfo/python-list
Re: initializing with empty list as default causes freaky problems
Reckoner wrote: Hi, Observe the following: In [202]: class Foo(): .: def __init__(self,h=[]): .: self.h=h .: .: In [203]: f=Foo() In [204]: g=Foo() In [205]: g.h Out[205]: [] In [206]: f.h Out[206]: [] In [207]: f.h.append(10) In [208]: f.h Out[208]: [10] In [209]: g.h Out[209]: [10] The question is: why is g.h updated when I append to f.h? Shouldn't g.h stay []? What am I missing here? I'm using Python 2.5.1. Thanks in advance. This is a FAQ (and *very* common newbie trap)! See: http://www.python.org/doc/faq/general/#why-are-default-values-shared-between-objects Gary Herron -- http://mail.python.org/mailman/listinfo/python-list
Re: initializing with empty list as default causes freaky problems
On Mon, Jul 27, 2009 at 1:40 PM, Reckoner wrote: > Hi, > > Observe the following: > > In [202]: class Foo(): > .: def __init__(self,h=[]): > .: self.h=h > .: > .: > > In [203]: f=Foo() > > In [204]: g=Foo() > > In [205]: g.h > Out[205]: [] > > In [206]: f.h > Out[206]: [] > > In [207]: f.h.append(10) > > In [208]: f.h > Out[208]: [10] > > In [209]: g.h > Out[209]: [10] > > The question is: why is g.h updated when I append to f.h? Shouldn't > g.h stay []? > > What am I missing here? > > I'm using Python 2.5.1. > > Thanks in advance. . It has to do with the way Python handles functions and class methods. Basically, when the parser creates the class Foo, it also creates all of Foo's class variables and functions. It's at this point, and only at this point, that the default parameter is evaluated. When you make an instance of Foo, just wraps the function __init__ by filling in the initial parameter. Because both f and g are really using the Foo.__init__ function (as opposed to separate f.__init__ and g.__init__ methods), they share the same default parameter, a list that was created at the very beginning. Since f.h and g.h both refer to the same list, updating f.h will also update g.h (and the default parameter). That's why it's a bad idea to use mutable default parameters- use either None class Foo(object) : def __init__(self, h=None) : if h is None: h = [] or, if None is an acceptable value, make a sentinel value sentinel = object() class Foo(object) : def __init__(self, h = sentinel) : if h is sentinel: h = [] > -- > http://mail.python.org/mailman/listinfo/python-list > -- http://mail.python.org/mailman/listinfo/python-list
Re: initializing with empty list as default causes freaky problems
Reckoner wrote: Hi, X-Antispam: NO; Spamcatcher 5.2.1. Score 50 Observe the following: In [202]: class Foo(): .: def __init__(self,h=[]): .: self.h=h .: .: In [203]: f=Foo() In [204]: g=Foo() In [205]: g.h Out[205]: [] In [206]: f.h Out[206]: [] In [207]: f.h.append(10) In [208]: f.h Out[208]: [10] In [209]: g.h Out[209]: [10] The question is: why is g.h updated when I append to f.h? Shouldn't g.h stay []? What am I missing here? I'm using Python 2.5.1. Default arguments are evaluated once and then shared, so don't use them with mutable objects like lists. Do this instead: class Foo(): def __init__(self, h=None): if h is None: self.h = [] else: self.h = h -- http://mail.python.org/mailman/listinfo/python-list
initializing with empty list as default causes freaky problems
Hi, Observe the following: In [202]: class Foo(): .: def __init__(self,h=[]): .: self.h=h .: .: In [203]: f=Foo() In [204]: g=Foo() In [205]: g.h Out[205]: [] In [206]: f.h Out[206]: [] In [207]: f.h.append(10) In [208]: f.h Out[208]: [10] In [209]: g.h Out[209]: [10] The question is: why is g.h updated when I append to f.h? Shouldn't g.h stay []? What am I missing here? I'm using Python 2.5.1. Thanks in advance. -- http://mail.python.org/mailman/listinfo/python-list