[Tutor] Fwd: Self, Scopes and my unbelievable muddleheadedness.

Luke Paireepinart rabidpoobear at gmail.com
Fri Oct 27 00:15:30 CEST 2006


doug shawhan wrote:
> [lots of stuff!]
You seem to have a penchant for choosing entertaining, albeit confusing, 
words to explain what you're thinking.
I have a similar inclination; however, I'll attempt to avoid this so 
that my explanation will make more sense :)

Now we begin.

First, an example, then an explanation.

#given the following definition...
class AClass(object):
    aClassVariable = 'Hello'
    def aMethod(self):
        print self.hello
    def __init__(self):
        self.hello = "Hi!"

  
 >>> AClass.aClassVariable
'Hello'
 >>> anInstance = AClass()
 >>> AClass.hello
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in ?
    AClass.hello
AttributeError: type object 'AClass' has no attribute 'hello'
 >>> anInstance.hello
'Hi!'
 >>> AClass.aMethod()
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in ?
    AClass.aMethod()
TypeError: unbound method aMethod() must be called with AClass instance 
as first argument (got nothing instead)
 >>> anInstance.aMethod()
Hi!
 >>> anInstance.aClassVariable
'Hello'
 >>> anInstance.aClassVariable = 'Ho!'
 >>> anInstance.aClassVariable
'Ho!'
 >>> AClass.aClassVariable
'Hello'

#---- end of example.

Believe it or not, this short example should tell you everything you 
need to know about objects ;)
However, that doesn't mean it makes any sense!
So I will try to explain it.
I had a huge problem with Objects when I first ran into them, but now 
they're easy to understand.
Hope I can do the same for you.


Okay, take this example:

class aClass(object):
    aVariable = 'hi'

What the interpreter does is creates a variable called aClass that 
points to this object.
Yes, class definitions are objects.
 >>> aClass
<class '__main__.aClass'>

Since the variable that we defined in the aClass object was defined in 
the main scope of the class,
and not in a class method (it wasn't defined inside a function that was 
in the class) it's global to the class object.
so...
 >>> aClass.aVariable
'hi'

we don't even need to make an instance of the class to access this variable.
We can make an instance if we want...
 >>> b = aClass()
 >>> b.aVariable
'hi'

But there's really no point, is there?

Now take this class.

class aClass(object):
    value = 'hi'
    def __init__(self):
          self.value = 'hello'

Because the 'self.value' is only defined inside of the '__init__' 
method, it's not global to the class definition,
but the 'value' variable is global to the class definition.

 >>> aClass.value
'hi'

But when we make an instance of this class,

 >>> instance = aClass()

The init method is called,

 >>> instance.value
'hello'

which replaces the class-global 'value' variable with the  
instance-global 'self.variable' version.

One thing it's important to note is this:

#given these two definitions
class aClass(object):
    aVar = 1
    aList = [1,2,3]

b = aClass()

#we get this.
 >>> aClass.aVar
1
 >>> aClass.aList
[1, 2, 3]
 >>> b.aVar
1
 >>> b.aList
[1, 2, 3]
 >>> b.aVar = 23
 >>> b.aList.append(4)
 >>> b.aVar
23
 >>> b.aList
[1, 2, 3, 4]
 >>> aClass.aVar
1
 >>> aClass.aList
[1, 2, 3, 4]

Notice how changing the value of b.aList changes the value of 
aClass.aList?  So any object you make after this,
 >>> a = aClass()
 >>> a.aList
[1, 2, 3, 4]

will have the modified value of aList,
 >>> a.aVar
1

but not the modified version of aVar.

However, if you were to change aVar in the class definition (and not in 
an instance of the class)
 >>> aClass.aVar = 2
 >>> a.aVar
2

then the value of aVar is changed.
This is interesting and a little scary, since changing a list in an 
instance can change this list in all class instances,
but not if it's an integer or a tuple or something else.
This is a good reason to use 'self'.

That way, each class has its own set of data that can't be messed with.

You say in your e-mail
"
Does it follow that if one does not prepend "self" to the variable, any 
change will affect all instances of an object (say in a threading 
situation)? That is the only thing that seems to make sense to me, 
otherwise "self" would just be silly.
"

No, this is not the point of self at all.

Imagine that you have this class.

class Poem(object):
    def __init__(self,title,text): #args: string, list of strings
       self.title = title
       self.text = text
    def readPoem(self):
       print "Poem: %s" % self.title
       for line in self.text:
          print line
    def reversePoem(self):
        self.text.reverse()

Now say you want two poems...
 >>> aolHaiku = Poem('Unwanted AOL CD Haiku',['A shiny let-down,','AOL 
CDs are good','Only for artwork'])
 >>> windowsHaiku = Poem('Microsoft Haiku',['Yesterday it 
worked.','Today it is not working.','Windows is like that.'])

And you want to read them.

 >>> aolHaiku.readPoem()
Poem: Unwanted AOL CD Haiku
A shiny let-down,
AOL CDs are good
Only for artwork

 >>> windowsHaiku.readPoem()
Poem: Microsoft Haiku
Yesterday it worked.
Today it is not working.
Windows is like that.

So it doesn't matter to us what's acually _in_ each class instance, we 
know if we call the readPoem on the Poem object, it'll do something.
similarly,

 >>> aolHaiku.reversePoem()
 >>> aolHaiku.readPoem()
Poem: Unwanted AOL CD Haiku
Only for artwork
AOL CDs are good
A shiny let-down,


Do you see the point?
an object has a specific set of data on which it operates with a 
specific set of methods.
So you create a generic template (the class definition) which people 
create instances of to hold their own data.
Or, if your class doesn't do exactly what they want, they can make their 
own class definition based on yours!
example:

class myPoemClass(Poem):
    def readPoem(self):
       print "The title of this poem is: %s" % self.title
       print "The text of the poem is as follows:"
       for line in self.text: print line


when we use this,

 >>> aolHaiku = myPoemClass('Unwanted AOL CD Haiku',['A shiny 
let-down,','AOL CDs are good','Only for artwork'])
#we created the same poem in our new class.

 >>> aolHaiku.readPoem()
The title of this poem is: Unwanted AOL CD Haiku
The text of the poem is as follows:
A shiny let-down,
AOL CDs are good
Only for artwork
#the output is different,

 >>> aolHaiku.reversePoem()
#but since we didn't declare a reversePoem function in our derived class,
 >>> aolHaiku.readPoem()
The title of this poem is: Unwanted AOL CD Haiku
The text of the poem is as follows:
Only for artwork
AOL CDs are good
A shiny let-down,
#it still reverses it like it did before.

Are you starting to see the benefits of classes?
I hope so!

To summarize,
the purpose of self is so you don't have to define data for each 
function in your class.
You define the data once (probably in the initialization of your class) 
and then it's defined throughout that instance (as long as you pass the 
instance variable around).
So the function reversePoem and readPoem didn't have to know how to get 
the data 'self.text' or 'self.title', it was just available to them.
It could've gotten there from the __init__ method, or any other method 
of the class.

Another example that might help, or might just confuse further:

 >>> class aClass(object):
    def __init__(self):
        self.variable = 'hello!'
    def printVariable(self):
        print self.variable

 >>> an_instance = aClass()
 >>> an_instance.printVariable()
hello!
 >>> aClass.printVariable(an_instance)
hello!

If you understand this, you probably understand self.

Hope that helps,
reply with anything that doesn't make sense, or just to tell me that I 
wasted my time and didn't address any issues you actually had :)
-Luke


More information about the Tutor mailing list