ленивая инициализация

May 22, 2010 19:47

 
до сих пор помню что когда ради интереса попробовал написать [объектноориентированный] HellowWorld в среде Visual Basic (а было это ещё лет 7~10 назад) -- то заметил что конструкторы декларированных в коде объектов -- не начнут создавать эти объекты, пока к этому объекту не будет никакого обращения!

(ну тоесть -- зачем зря создавать объекты , пока ими никто не начнёт пользоваться(?).. а вдруг часть объектов так и останеться непользованной!)

...вот подумать.. .... .... Basic -- этож какойто ГОВНОязык... :-) а получается ведь что там есть элементы ленивости x_X [ну по крайней мере в интерпритации Microsoft Visual Basic :-) :-) ] ...

поэтому... вот что я думаю про ленивость инициализаций в Python:

механизм который поможет её создать -- можно описать следущим образом:

# require Python2 or Python3 #-*- coding: UTF-8 *-* import threading class SimpleLazyProxy:     '''ленивая инициализация объекта     безопасная для многонитевого использования'''     def __init__(self, factory):         self.__lock = threading.RLock()         self.__obj = None         self.__factory = factory     def __call__(self):         '''функция для доступа к настоящему объекту         если объект не создан, то он создаcтся'''         # пробуем получить "быстрый" доступ к объекту:         obj = self.__obj         if obj is not None:             # получилось!             return obj         else:             # объект возможно ещё не создан             with self.__lock:                 # получаем доступ к объекту в эксклюзивном режиме:                 obj = self.__obj                 if obj is not None:                     # оказалось объект уже создан.                     #     не будем повторно его создавать                     return obj                 else:                     # объект действительно ещё не создан.                     #     создадим же его!                     obj = self.__factory()                     self.__obj = obj                     return obj     __getattr__ = lambda self, name: \         getattr(self(), name) def lazy(proxy_cls=SimpleLazyProxy):     '''декоратор превращающий класс, в класс с ленивой инициализацией     средствами Proxy-класса'''     class ClassDecorator:         def __init__(self, cls):             # инициализация декоратора,             #     но не декорируемого класса и не Proxy-класса             self.cls = cls         def __call__(self, *args, **kwargs):             # запрос инициализации Proxy-класса             # передадим Proxy-классу нужные параметры             #     для инициализации декорируемого класса             return proxy_cls(lambda: self.cls(*args, **kwargs))     return ClassDecorator # простая проверка: def test_0():     print('\t\t\t*** Начало теста ***')     import time     @lazy() # экземпляры этого класса будут с ленивой инициализацией     class TestType:         def __init__(self, name):             print('%s: Создаётся...' % name)             # искусственно увеличим время создания объекта,             #     для нагнетения конкуренции нитей             time.sleep(3)             self.name = name             print('%s: Создался!' % name)         def test(self):             print('%s: Проверка' % self.name)     # один такой экземпляр будет взаимодействовать с несколькими нитями     test_obj = TestType('Межнитевый тестовый объект')     target_event = threading.Event()     def threads_target():         # функция которую будут выполнять нити:         # ждём наступления специального события         target_event.wait()         # как только это событие наступит --         #     все 10 нитей одновременно обратятся к тестовому объекту         #     и в этот момент он инициализируется, в одной из нитей         test_obj.test()     # создадим этих 10 нитей, с вышеописанным алгоритмом threads_target()     threads = []     for thread in range(10):         thread = threading.Thread(target=threads_target)         thread.start()         threads.append(thread)     print('До этого момента обращений к объекту не было')     # подождём немного времени...     time.sleep(3)         # ...и одновременно запустим test_obj.test() во всех нитях     print('Активируем событие для использования тестового объекта!')     target_event.set()     # завершение     for thread in threads:         thread.join()     print('\t\t\t*** Конец теста ***')

совсем вроде бы не геморойно :-D :-D

хотя..... при этом получаем разумеется и определённые негативы :-)..

...такие как -- все экземпляры ленивых классов -- на самом деле будут экземплярами Proxy-классов... а значит с ними нельзя будт так свободно работать как с обыкновеннымми экземплярами оригинального класса! (хотя конешно никто не запретит в любое время извлеч из Proxy-экземпляра -- настоящщий оригинальный экземпляр! :)) ну а для некоторых типов объектов -- даже и интерфейс Proxy-класса вполне будет хватать :-)

вобщем, думаю... хотябы кое-где -- это должно иметь место жить :-) :-)

Previous post Next post
Up