Inexplicable behavior in simple example of a set in a class

Chris Rebert clp2 at rebertia.com
Sat Jul 2 19:25:45 EDT 2011


On Sat, Jul 2, 2011 at 3:23 PM, Saqib Ali <saqib.ali.75 at gmail.com> wrote:
>> Instance variables are properly created in the __init__()
>> initializer method, *not* directly in the class body.
>>
>> Your class would be correctly rewritten as:
>>
>> class MyClass2(object):
>>     def __init__(self):
>>         self.mySet = sets.Set(range(1,10))
>>
>>     def clearSet(self):
>> # ...rest same as before...
>
>
> Thanks Chris. That was certainly very helpful!!
>
> So just out of curiosity, why does it work as I had expected when the
> member contains an integer, but not when the member contains a set?

To explain that, one must first understand that name lookup on an
object looks in the following places, in order:
1. the instance itself
2. the instance's class
3. the instance's superclasses

So, if we have:

class Foo(object):
    bar = 7
foo_inst = Foo()

then both `foo_inst.bar` and `Foo.bar` refer to the same value.

However, if we then do:

foo_inst.bar = 42

then we'll have:

foo_inst.bar == 42 and Foo.bar == 7


Now back to your actual question. In clearNum(), you do:
    self.myNum = 0
which creates a *new* instance variable that shadows the class
variable of the same name, like in my example. If you check, you'll
indeed see that myClass1.myNum is still 9 after calling clearNum().

By contrast, in clearSet() you do:
    self.mySet.clear()
which just mutates the existing Set object in-place. No new variable
is created, and mySet is still a class variable and thus shared by all
instances.

Further reading:
http://effbot.org/zone/python-objects.htm
http://effbot.org/zone/call-by-object.htm

Cheers,
Chris
--
http://rebertia.com



More information about the Python-list mailing list