How do python classes work?
<p>I have a code file from the boto framework pasted below, all of the print statements are mine, and the one commented out line is also mine, all else belongs to the attributed author.</p>

<p>My question is what is the order in which instantiations and allocations occur in python when instantiating a class?  The author's code below is under the assumption that 'DefaultDomainName' will exist when an instance of the class is created (e.g. __init__() is called), but this does not seem to be the case, at least in my testing in python 2.5 on OS X.  </p>

<p>In the class Manager __init__() method, my print statements show as 'None'.  And the print statements in the global function set_domain() further down shows 'None' prior to setting Manager.DefaultDomainName, and shows the expected value of 'test_domain' after the assignment.  But when creating an instance of Manager again after calling set_domain(), the __init__() method still shows 'None'.</p>

<p>Can anyone help me out, and explain what is going on here.  It would be greatly appreciated.  Thank you.</p>

<pre>
<code>

# Copyright (c) 2006,2007,2008 Mitch Garnaat http://garnaat.org/
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, dis-
# tribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the fol-
# lowing conditions:
#
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

import boto
from boto.utils import find_class

class Manager(object):

    DefaultDomainName = boto.config.get('Persist', 'default_domain', None)

    def __init__(self, domain_name=None, aws_access_key_id=None, aws_secret_access_key=None, debug=0):
        self.domain_name = domain_name
        self.aws_access_key_id = aws_access_key_id
        self.aws_secret_access_key = aws_secret_access_key
        self.domain = None
        self.sdb = None
        self.s3 = None
        if not self.domain_name:
            print "1: %s" % self.DefaultDomainName
            print "2: %s" % Manager.DefaultDomainName
            self.domain_name = self.DefaultDomainName
            #self.domain_name = 'test_domain'
            if self.domain_name:
                boto.log.info('No SimpleDB domain set, using default_domain: %s' % self.domain_name)
            else:
                boto.log.warning('No SimpleDB domain set, persistance is disabled')
        if self.domain_name:
            self.sdb = boto.connect_sdb(aws_access_key_id=self.aws_access_key_id,
                                        aws_secret_access_key=self.aws_secret_access_key,
                                        debug=debug)
            self.domain = self.sdb.lookup(self.domain_name)
            if not self.domain:
                self.domain = self.sdb.create_domain(self.domain_name)

    def get_s3_connection(self):
        if not self.s3:
            self.s3 = boto.connect_s3(self.aws_access_key_id, self.aws_secret_access_key)
        return self.s3

def get_manager(domain_name=None, aws_access_key_id=None, aws_secret_access_key=None, debug=0):
    return Manager(domain_name, aws_access_key_id, aws_secret_access_key, debug=debug)

def set_domain(domain_name):
    print "3: %s" % Manager.DefaultDomainName
    Manager.DefaultDomainName = domain_name
    print "4: %s" % Manager.DefaultDomainName

def get_domain():
    return Manager.DefaultDomainName

def revive_object_from_id(id, manager):
    if not manager.domain:
        return None
    attrs = manager.domain.get_attributes(id, ['__module__', '__type__', '__lineage__'])
    try:
        cls = find_class(attrs['__module__'], attrs['__type__'])
        return cls(id, manager=manager)
    except ImportError:
        return None

def object_lister(cls, query_lister, manager):
    for item in query_lister:
        if cls:
            yield cls(item.name)
        else:
            o = revive_object_from_id(item.name, manager)
            if o:
                yield o
</code>
</pre>
