Weird Python behaviour
Francesco Bochicchio
bieffe62 at gmail.com
Tue Aug 10 11:01:07 EDT 2010
On 10 Ago, 13:58, Jonas Nilsson <j... at 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
More information about the Python-list
mailing list