Postpone creation of attributes until needed

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Mon Jun 11 12:21:51 CEST 2007


On Mon, 11 Jun 2007 02:24:51 -0700, Frank Millman wrote:

> Hi all
> 
> I have a small problem. I have come up with a solution, but I don't
> know if it is a) safe, and b) optimal.
> 
> I have a class with a number of attributes, but for various reasons I
> cannot assign values to all the attributes at __init__ time, as the
> values depend on attributes of other linked classes which may not have
> been created yet. I can be sure that by the time any values are
> requested, all the other classes have been created, so it is then
> possible to compute the missing values.

Unless you're doing something like creating classes in one thread while
another thread initiates your instance, I don't understand how this is
possible.

Unless... you're doing something like this?


def MyClass(object):
    def __init__(self):
        self.x = Parrot.plumage   # copy attributes of classes
        self.y = Shrubbery.leaves


Maybe you should force the creation of the classes?

def MyClass(object):
    def __init__(self):
        try:
            Parrot
        except Some_Error_Or_Other: # NameError?
            # do something to create the Parrot class
            pass
        self.x = Parrot.plumage
        # etc.


> At first I initialised the values to None, and then when I needed a
> value I would check if it was None, and if so, call a method which
> would compute all the missing values. However, there are a number of
> attributes, so it got tedious. I was looking for one trigger point
> that would work in any situation. This is what I came up with.
> 
>>>> class A(object):
> ...    __slots__ = ('x','y','z')

By using slots, you're telling Python not to reserve space for a __dict__,
which means that your class cannot create attributes on the fly.



> ...    def __init__(self,x,y):
> ...        self.x = x
> ...        self.y = y
> ...    def __getattr__(self,name):
> ...        print 'getattr',name
> ...        if name not in self.__class__.__slots__:
> ...            raise AttributeError,name
> ...        self.z = self.x * self.y
> ...        return getattr(self,name)

[snip]

> In other words, I do not declare the unknown attributes at all. This
> causes __getattr__ to be called when any of their values are
> requested, and __getattr__ calls the method that sets up the
> attributes and computes the values.
> 
> I use __slots__ to catch any invalid attributes, otherwise I would get
> a 'maximum recursion depth exceeded' error.

That's the wrong solution to that problem. To avoid that problem,
__getattr__ should write directly to self.__dict__.


> Is this ok, or is there a better way?

At the interactive Python prompt: 

help(property)



-- 
Steven




More information about the Python-list mailing list