Создание класса LazilyEvaluatedConstantProperty в Python - PullRequest
1 голос
/ 16 июля 2010

В Python я хочу кое-что сделать, похожую на встроенную property, которую я не знаю, как это сделать.

Я называю этот класс LazilyEvaluatedConstantProperty.Он предназначен для свойств, которые должны рассчитываться только один раз и не изменяться, но они должны создаваться лениво, а не при создании объекта, для производительности.

Вот использование:

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)

Вы можете видеть, что использование похоже на property, за исключением того, что есть только геттер, и нет установщика или удалителя.

Предполагается, что при первом доступе к my_object.personality метод _get_personalityвызываться, и тогда результат будет кэширован, и _get_personality никогда больше не будет вызываться для этого объекта.

В чем моя проблема с реализацией этого?Я хочу сделать что-то немного хитрое для улучшения производительности: я хочу, чтобы после первого доступа и _get_personality вызова personality стал атрибутом данных объекта, поэтому поиск будет быстрее при последующих вызовах.Но я не знаю, как это возможно, поскольку у меня нет ссылки на объект.

У кого-нибудь есть идея?

1 Ответ

1 голос
/ 16 июля 2010

Я реализовал это:

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

В будущем поддерживаемую реализацию, вероятно, можно найти здесь:

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

...