Prev: freeze function calls
Next: shelf-like list?
From: Jonas Nilsson on 10 Aug 2010 07:58 Hello, Lets say that I want to feed an optional list to class constructor: class Family(): def __init__(self, fName, members = []): self.fName = fName self.members = members Now, lets add members to two different instances of Family: f1 = Family("Smith") f1.members.append("Bill") f2 = Family("Smithers") f2.members.append("Joe") Finally, lets look at the members in the Smithers family: print f2.members output: ['Bill', 'Joe'] Why on earth is the output ['Bill', 'Joe']!? Is there a simple solution that separates f1 and f2 without forcing me to write code for the special case when you don't feed members to the __init__()-function? /Jonas
From: Peter Otten on 10 Aug 2010 08:18 Jonas Nilsson wrote: > Lets say that I want to feed an optional list to class constructor: > > class Family(): > def __init__(self, fName, members = []): > Why on earth is the output ['Bill', 'Joe']!? Is there a simple > solution that separates f1 and f2 without forcing me to write code for > the special case when you don't feed members to the __init__()-function? Congrats; you just encountered a very popular new trap ;) The most recent explanation is only one day old: http://mail.python.org/pipermail/python-list/2010-August/1252316.html Peter
From: Benjamin Kaplan on 10 Aug 2010 10:43 On Tue, Aug 10, 2010 at 4:58 AM, Jonas Nilsson <jmnc(a)spray.se> wrote: > Hello, > > Lets say that I want to feed an optional list to class constructor: > > class Family(): > def __init__(self, fName, members = []): > self.fName = fName > self.members = members > > Now, lets add members to two different instances of Family: > > f1 = Family("Smith") > f1.members.append("Bill") > > f2 = Family("Smithers") > f2.members.append("Joe") > > Finally, lets look at the members in the Smithers family: > > print f2.members > output: ['Bill', 'Joe'] > > Why on earth is the output ['Bill', 'Joe']!? Is there a simple solution that > separates f1 and f2 without forcing me to write code for the special case > when you don't feed members to the __init__()-function? > > /Jonas In python, a function definition is an executable statement, not a declaration. Default args only get evaluated once- when the function is first created. You have to use a sentinel value and create the object inside the function if you want it to get executed every time. class Family(): def __init__(self, fName, members = None): if members is None : members = [] self.fName = fName self.members = members If None is a valid argument to this function, then make a dummy object and check identity (to make sure it's *that* object and not just something that evaluates equal). sentinel = object() def something_that_accepts_none(foo = sentinel) : if foo is sentinel : foo = {} # other stuff
From: Francesco Bochicchio on 10 Aug 2010 11:01 On 10 Ago, 13:58, Jonas Nilsson <j...(a)spray.se> wrote: > Hello, > > Lets say that I want to feed an optional list to class constructor: > > class Family(): > def __init__(self, fName, members = []): > self.fName = fName > self.members = members > > Now, lets add members to two different instances of Family: > > f1 = Family("Smith") > f1.members.append("Bill") > > f2 = Family("Smithers") > f2.members.append("Joe") > > Finally, lets look at the members in the Smithers family: > > print f2.members > output: ['Bill', 'Joe'] > > Why on earth is the output ['Bill', 'Joe']!? Is there a simple > solution that separates f1 and f2 without forcing me to write code for > the special case when you don't feed members to the __init__()-function? > > /Jonas You stumbled in two python common pitfalls at once :-) One, the default arguments issue, was already pointed to you. The other one is that python variables are just names for objects. Assigning a variable never mean making a copy, it just means using another name for the same object. There used to be a very nice (also graphic) explanationor this somewhere on the web, but my googling skills failed me this time, so instead I'll show you the concept using your own code: >>> class Family: .... def __init__(self, fName, members = []): .... self.fname = fName .... self.members = members .... >>> mlist = ["Bill"] >>> f1 = Family("Smiths", mlist ) >>> mlist.append( "John" ) # attempt to not-so-clever reyse of the sme variable >>> f2 = Family("Smithers", mlist ) >>> f1.members ['Bill', 'John'] Now my example is a bit contrieved but I'm sure you got the idea : in your example is better to copy the list with self.members = members[:]. Better yet, you could make use of python arguments grouping feature : >>> class Family: .... def __init__(self, fName, *members ): .... self.members = list(members) # because members is a tuple .... self.fname = fName .... >>> f1 = Family("Smith") >>> f1.members.append("Bill") >>> f2 = Family("Smithers") >>> f2.members.append("Joe") >>> f2.members ['Joe'] >>> f1.members ['Bill'] This solves your "no initial member" special case and allows for an easier syntax for creating class instances (no brackets involved) >>> f3 = Family("Bochicchio", "Angelo", "Francesco", "Mario") >>> f3.members ['Angelo', 'Francesco', 'Mario'] >>> Ciao ---- FB
From: Stefan Schwarzer on 10 Aug 2010 11:57
Hi, On 2010-08-10 17:01, Francesco Bochicchio wrote: > There used to be a very nice (also graphic) explanationor this > somewhere on the web, but my googling skills failed me this time, > so instead I'll show you the concept using your own code: Probably this isn't the page you're referring to, but I only recently gave a beginners' talk at EuroPython: http://sschwarzer.com/download/robust_python_programs_europython2010.pdf The topic of identity and assignments starts on slide 7, nice graphics start on slide 10. ;-) Stefan |