[Tutor] multiple class instances

Corran Webster cwebster@math.tamu.edu
Mon, 10 May 1999 12:58:18 -0500 (CDT)


>> > You use class members which means when creating an instance of class
>> > Spam and assigning 'I\'ll have the spam' to it's choice member you
>> > modify the choice in the CLASS your instance is made from not the
>> > instance itself. So when creating a second instance it is based on the
>> > 'modified' Spam class.
>> 
>> What you've written isn't correct:
> 
> I appologize! I don't want to confuse anybody - I'm a tutee (or what's
> the name of people learning from the tutors?), so plase forgive me. It

No problem, and no need to apologise - sorry if I came over as hostile.

> was more an exercise for myself, and I new that someone of the tutors
> will correct me if I was wrong ;-) ... . So maybe bith of us Ken and me
> learned something.

Indeed - I got bitten by this one myself when I was learning because it
is a bit counter-intuitive - once you discover that there _are_ class
variables you sort of expect them to behave in a C++-ish sort of way.

> Hm, I try so summarize what I think've just learned:
> 
> 1. 
> class Bla:
> 	choice = 'default'
> 
> This is a class variable
> 
> 2. class variables can be accessed via the Class itself
>  Bla.default
> 
> 3. or via an instance:
> x = Bla()
> x.choice

This is right.

> 4. changeing the class variable via the class will not affect the
> already created instances but the future ones

This is not quite the whole story - if you change the class variable
"Bla.choice = whatever" then "x.choice" will also change _provided_ you
haven't previously changed the value.

If you think of variables as references to objects, it's easier to
understand what's going on:

When you define the class Bla, you create an object (the string
"default") in your example, which is referenced by the variable
"Bla.choice".

When you create instances of Bla, they don't have any object associated
with "x.choice" - if you try to access the value, Python says "oh - I
don't see an x.choice... but look! x is a Bla, and there's a
Bla.choice, I'll use that instead".

However, if you try to _set_ x.choice to something (say the string
"Wibble"), Python says "oh - I don't see an x.choice... so I'll create a
new variable "x.choice" which refers to this object "Wibble").  No
whenever you try and access "x.choice", Python says "Aha! I have
x.choice right here" and never gets around to noticing that there is
also a Bla.choice.

Changing Bla.choice will change the object that Bla.choice points to,
and it will _appear_ to change the object that any y.choice points to as
long as you haven't _changed_ y.choice previously.

From a practical standpoint, "y.choice" will give you the current value
of "Bla.choice", irrespective of when y was created, until such time as
you say "y.choice = whatever".

This is much the same sort of behaviour as local function variables,
compare:

a = 5      #global var

def f():
  print a  #print the global var a

def g():
  a = 7    #create a local var a
  print a  #print the local var

Python is going through the same sort of process here: in f Python says
"Oh - there's no local variable a... but look, there is a global
variable a, I'll use its value!"

In g Python says "Ah, I'll set the local variable a to 7" and then when
it comes time to print, Python says "Oh look, a is a local variable,
I'll use it's value".

So it all makes sense when you think of it this way, but from a C/C++
perspective it's sort of odd.

> 5. Class variables may be used when a sort of template is needed for
> certian variables - the instance may change this variable according it's
> personal needs ..., 

This is right.  But you can also change the template value dynamically
should you so desire.

> 6. It's realy difficult to decide when to use an __init__ funtion with
> 'self.variable' and when to use class variables (they can do the same,
> can't they?). Sorry for that but it's all bit cryptic for me :-(

The main difference is that class variables allow "retroactive change"
of default values as discussed above, instance variables are completely
independent of one another.

There are also differences when you have _mutable_ objects like lists. 
Remember that variables are really references to objects, so if the
object is mutable and you change it, it will appear to change for all
other references to it.  For example:

Python 1.5.2 (#2, Apr 15 1999, 13:12:41)  [GCC 2.7.2] on sunos5
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> class Bla:
...   choices = ['spam', 'spam and eggs', 'spam, spam, spam and eggs']
... 
>>> x = Bla()
>>> x.choices[1] = 'eggs and spam'
>>> print Bla.choices
['spam', 'eggs and spam', 'spam, spam, spam and eggs']

Which leads to the infamous default method gotcha:

class Bla:
  def __init__(self, mylist = []):
    self.mylist = mylist

(note: can be any method, not just __init__)

For the tutees: the default argument [] is actually an anonymous class
variable - so this construct means that for each instance the variable
x.mylist refers to the same mutable object

>>> x = Bla()
>>> y = Bla()
>>> print y.mylist
[]
>>> x.mylist.append('a')
>>> print y.mylist
['a']

Everyone gets bitten by this at least once.  A good idiom to do what
you _want_ to do in this case is:

class Bla:
  def __init__(self, mylist = None):
    self.mylist = mylist or []


> 	sorry for confusion and thanks for help,

No problem - there's a Zen to Python variables and objects. Once you
get it, you're fine, but it's probably the most unintuitive aspect of
the language for those who have been trained in something like C or
Pascal.

Corran