开发者

Making a LazilyEvaluatedConstantProperty class in Python

There's a little thing I want to do in Python, similar to the built-in property, that I'm not sure how to do.

I call this class LazilyEvaluatedConstantProperty. It is intended for properties that should be calculated only once and do not change, but they should be created lazily rather than on object creation, for performance.

Here's the usage:

开发者_开发知识库class MyObject(object):

    # ... Regular definitions here

    def _get_personality(self):
        # Time consuming process that creates a personality for this object.
        print('Calculating personality...')
        time.sleep(5)
        return 'Nice person'

    personality = LazilyEvaluatedConstantProperty(_get_personality)

You can see that the usage is similar to property, except there's only a getter, and no setter or deleter.

The intention is that on the first access to my_object.personality, the _get_personality method will be called, and then the result will be cached and _get_personality will never be called again for this object.

What is my problem with implementing this? I want to do something a bit tricky to improve performance: I want that after the first access and _get_personality call, personality will become a data attribute of the object, so lookup will be faster on subsequent calls. But I don't know how it's possible since I don't have a reference to the object.

Does anyone have an idea?


I implemented it:

class CachedProperty(object):
    '''
    A property that is calculated (a) lazily and (b) only once for an object.

    Usage:

        class MyObject(object):

            # ... Regular definitions here

            def _get_personality(self):
                print('Calculating personality...')
                time.sleep(5) # Time consuming process that creates personality
                return 'Nice person'

            personality = CachedProperty(_get_personality)

    '''
    def __init__(self, getter, name=None):
        '''
        Construct the cached property.

        You may optionally pass in the name that this property has in the
        class; This will save a bit of processing later.
        '''
        self.getter = getter
        self.our_name = name


    def __get__(self, obj, our_type=None):

        if obj is None:
            # We're being accessed from the class itself, not from an object
            return self

        value = self.getter(obj)

        if not self.our_name:
            if not our_type:
                our_type = type(obj)
            (self.our_name,) = (key for (key, value) in 
                                vars(our_type).iteritems()
                                if value is self)

        setattr(obj, self.our_name, value)

        return value

For the future, the maintained implementation could probably be found here:

https://github.com/cool-RR/GarlicSim/blob/master/garlicsim/garlicsim/general_misc/caching/cached_property.py

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜