ASPN ActiveState Programmer Network
sign in | join ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups | Web Services
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: lazy attributes
Submitter: Sébastien Keim (other recipes)
Last Updated: 2002/06/07
Version no: 1.2
Category: OOP

 

5 stars 6 vote(s)


Description:

How to create attributes with 'computed at first use' values.

Source: Text Source

#
# first solution:
#

class sample(object):
    class one(object):
        def __get__(self, obj, type=None):
            print "computing ..."
            obj.one = 1
            return 1
    one = one()

x=sample()
print x.one
print x.one


#
# other solution:
#  

# lazy attribute descriptor
class lazyattr(object):
    def __init__(self, fget, doc=''):
        self.fget = fget
        self.__doc__ = doc
    def __appoint__(self, name, cl_name):
        if hasattr(self,"name"):
            raise SyntaxError, "conflict between "+name+" and "+self.name
        self.name = name        
    def __get__(self, obj, cl=None):
        if obj is None:
            return self
        value = self.fget(obj)
        setattr(obj, self.name, value)
        return value

# appointer metaclass:
# call the members __appoint__ method 
class appointer(type):
    def __init__(self, cl_name, bases, namespace):
        for name,obj in namespace.iteritems():
            try:
                obj.__appoint__(name, cl_name)
            except AttributeError:
                pass
        super(appointer, self).__init__(cl_name, bases, namespace)

# base class for lazyattr users
class lazyuser(object):
    __metaclass__ = appointer

# usage sample
class sample(lazyuser):
    def one(self):
        print "computing ..."
        return 1
    one  = lazyattr(one, "one lazyattr")

x=sample()
print x.one
print x.one
del x.one
print x.one

Discussion:

This recipe works only for Python >= 2.2.

When an attribute is expensive to compute, it's sometime desirable to delay this computing until the value is actually needed.

The first solution show how to create a lazy attribute "by hand"

The second solution allow to create this kind of attributes with a syntax similar to property attributes definition.
In the second solution, lazyattr user classes must inherit from lazyuser. This is needed for the lazyattr __appoint__ initialization.


I hope that this recipe can also be a good sample of metaclass and descriptor definitions.



Add comment

Number of comments: 1

clever!, Michele Simionato, 2003/07/05
This is an usage of descriptors I have never thought about ;)
Add comment

SEARCH
advanced | search help


Highest rated recipes:

1. Finite State Machine ...

2. General Class for ...

3. Lightweight XML ...

4. Reading and writing mbox ...

5. How to Set Environment ...

6. automatically upgrade ...

7. Stateful Objects use ...

8. Directory Walker ...

9. IPy Notify

10. Generator Attributes


Privacy Policy | Email Opt-out | Feedback | Syndication
© 2004 ActiveState, a division of Sophos All rights reserved