lazy initialization, python.

By masteddev

Наверное все знают зачем эта ленивая инициализация нужна и как, в общем случае, реализуется.
Для тех кто не знает, ниже я попытался, как мог, объяснить как оно работает. А еще ниже, привел пример кода декоратора, который немного упрощает реализацию “ленивой” инициализации в программах на питоне.

Кратко о “ленивой” инициализации.
Предположим, что у нас имеется некий объект класса A, в процессе работы этому объекту, для его внутренних нужд, может понадобится экземпляр класса VeryBigObject, а может и не понадобится, зависит от условий и событий происходящих во время выполнения программы. Мы знаем о том, что создание и инициализация объекта VeryBigObject займет большое время, а вероятность того, что он понадобится не очень велика, поэтому вместо инициализации экземпляр VeryBigObject во время инициализации объекта класса A мы бы хотели инициализировать объект VeryBigObject непосредственно перед его использованием, вот один из способов добиться такого поведения:

class A(object):
    def __init__(self):
        self.__lazy_attr = None

    @property
    def lazy_attr(self):
        if self.__lazy_attr is None:
            self.__lazy_attr = VeryBigObject()
        return self.__lazy_attr

    def process(self):
        try:
            ...
        except SomeRareError, error:
            self.__lazy_attr.process(error)
        except AnotherRareError, error:
            self.__lazy_attr.process(error)

Декоратор.
Сегодня мне наконец-то надоело писать один и тот-же код, а именно установку и проверку значений приватных атрибутов. Немного подумав выдумал вот такой декоратор, делающий за меня надоевшие телодвижения:

def lazy(func):
    @property
    def wrapper(self):
        attr_name = '__%s' % func.__name__
        try:
            value = getattr(self, attr_name)
        except AttributeError:
            value = func(self)
            setattr(self, attr_name, value)
        return value
    return wrapper

И сразу же пример того, как выглядел бы наш класс A, если бы мы использовали декоратор lazy:

class A(object):
    @lazy
    def lazy_attr(self):
        return VeryBigObject()
    ....

Декоратор работает очень просто, он оборачивает указанный метод, в нашем случае это lazy_attr .При этом обернутый метод становится свойством (property) объекта. Далее, при первом обращении к свойству, декоратор устанавливает приватный атрибут вида “__имя_свойства”, у нас это будет атрибут self.__lazy_attr. Значением которого является результат вызова обернутого метода и возвращает это значение. Обернутый нами метод lazy_attr вернет экземпляр VeryBigObject. При следующих обращениях декоратор просто берет из установленного им атрибута значение и возвращает его запросившей стороне.
Немного запутанно, но, я надеюсь, глядя на код вы разберетесь. :)

Метки:

2 коммент. на “lazy initialization, python.”

  1. » На заметку. Python. Lazy initialization » Blog Post » три точки:

    [...] programmizm описывает ленивую инициализацию. А также пример того, как можно использовать [...]

  2. Обзор №6, май 2008 - Design For Masters:

    [...] этом побочных эффектов и значительных неудобств.lazy initialization, python Ленивая инициализация и для чего она нужна, [...]

Ответить