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