Рецепты
декораторов
Юрий Юревич yury.yurevich@equelli.com | http://pyobject.ru

                PyCamp Kyiv, Киев, 2010.

...
О докладчике
●   Живу от Киева >2000 км
●   В области разработки ПО >7 лет
●   С Python >5 лет
●   Блог о Python >3 лет
● ...
О докладе
●   Ингредиенты
    ●   Функция — объект первого рода
    ●   Декоратор — обёртка
    ●   Синтаксический сахар
●...
Ингредиенты




              4
Ингредиенты (2)

Декоратор =
функции(объекты первого рода)
+ вложенные функции +
@синтаксический_сахар



                ...
Функция — объект первого рода
>>> def give_me_twice(x):
...     return x*2
...
>>> function
<function give_me_twice at 0xb...
Декоратор — обёртка функции
>>> def give_me_twice(x):
...     return x*2
...

>>> def make_strange(func)
...     replaced ...
Вложенные функции
>>> def give_me_twice(x):
...     return x*2
...

>>> def make_really_strange(func):
...     def wrapper...
Фабрика!
>>> def give_me_twice(x):
...     return x*2
...

>>> def make_really_omg(num):
...     def decor(func):
...     ...
Еще и классы
>>> def make_really_strange(func):       func → wrapper
...     def wrapper(z):
...         res = func(z + 2)...
Синтаксический сахар
  @name — неявный вызов name(func)
«Обычный»
>>> def give_me_twice(x):
...     return x*2
...

>>> gi...
Дайте два!
●   «снизу вверх»
●   «изнутри наружу»
●   Не очень красиво
@usecase
@render_to('usecase_research.html')
@useca...
Рецепты




          13
Декоратор —
  «вынесение общего
знаменателя за скобки»

   По сути, пересмотр паттернов ООП для Python
      и реализация ...
Инфраструктура




                 15
Инфраструктура
●   Изменяет окружение
●   Не меняет функцию/аргументы (обычно)
●   Примеры:
    ●   @commit
    ●   @cache...
Интерфейс




            17
Интерфейс
●   Регистрация однородных объектов
●   Проверка требований (опционально)
●   Примеры:
    ●   @register.tag (Dj...
Адаптер




          19
Адаптер
●   Согласование API, преобразование данных
●   Часто — фабрики
●   Примеры:
    ●   @render_to (Django, Александр...
Гард




       21
Гард
●   Вынос типичного условного перехода
●   Примеры:
    ●   @login_required (Django)
    ●   @validate (Pylons)
●   П...
Реальная жизнь - ajax_request
def ajax_request(func):
    def wrapper(request, *args, **kwargs):        гард
        if re...
Реальная жизнь - reg.simple_tag
def simple_tag(self, func):
    params, xx, xxx, defaults = getargspec(func)

   class Sim...
Кунг-фу



   Это к Сергею Щетинину ;)

   http://self.maluke.com/




                             25
P.S. Ссылки
●   http://www.siafoo.net/article/68
●   http://pypi.python.org/pypi/decorator
●   http://tinyurl.com/decorato...
Спасибо за внимание




Вопросы?
                      27
Upcoming SlideShare
Loading in …5
×

Decorators' recipes

1,620 views
1,552 views

Published on

Yury Yurevich's topic "Decorators' recipes" from PyCamp Kyiv 2010 (also known as PyKyiv)

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,620
On SlideShare
0
From Embeds
0
Number of Embeds
66
Actions
Shares
0
Downloads
23
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Decorators' recipes

  1. 1. Рецепты декораторов Юрий Юревич yury.yurevich@equelli.com | http://pyobject.ru PyCamp Kyiv, Киев, 2010. 1
  2. 2. О докладчике ● Живу от Киева >2000 км ● В области разработки ПО >7 лет ● С Python >5 лет ● Блог о Python >3 лет ● Конференция по Ruby&Python >2 лет 2
  3. 3. О докладе ● Ингредиенты ● Функция — объект первого рода ● Декоратор — обёртка ● Синтаксический сахар ● Рецепты ● Инфраструктура ● Интерфейс ● Адаптер ● Гард ● Примеры из реальной жизни 3
  4. 4. Ингредиенты 4
  5. 5. Ингредиенты (2) Декоратор = функции(объекты первого рода) + вложенные функции + @синтаксический_сахар 5
  6. 6. Функция — объект первого рода >>> def give_me_twice(x): ... return x*2 ... >>> function <function give_me_twice at 0xb76278b4> >>> def call_it(func, arg) ... return func(arg) ... >>> def make_strange(func) ... replaced = lambda x: func(x + 5) ... return replaced ... >>> strange_twice = make_strange(give_me_twice) 6
  7. 7. Декоратор — обёртка функции >>> def give_me_twice(x): ... return x*2 ... >>> def make_strange(func) ... replaced = lambda x: func(x + 5) ... return replaced ... >>> give_me_twice = make_strange(give_me_twice) декоратор 7
  8. 8. Вложенные функции >>> def give_me_twice(x): ... return x*2 ... >>> def make_really_strange(func): ... def wrapper(z): ... res = func(z + 2) ... return res ... return wrapper ... >>> give_me_twice = make_really_strange(give_me_twice) >>> give_me_twice <function wrapper at 0xb7570924> 8
  9. 9. Фабрика! >>> def give_me_twice(x): ... return x*2 ... >>> def make_really_omg(num): ... def decor(func): ... def wrapper(z): ... res = func(z + num) ... return res ... return wrapper ... return decor ... >>> decorator = make_really_omg(5) >>> decorator <function decor at 0xb7570336> >>> give_me_twice = decorator(give_me_twice) >>> give_me_twice <function wrapper at 0xb7570823> 9
  10. 10. Еще и классы >>> def make_really_strange(func): func → wrapper ... def wrapper(z): ... res = func(z + 2) ... return res ... return wrapper >>> class make_really_strange(object): func → <instance> ... def __init__(self, func): ... self.func = func ... def __call__(self, z): ... res = self.func(z + 2) ... return res 10
  11. 11. Синтаксический сахар @name — неявный вызов name(func) «Обычный» >>> def give_me_twice(x): ... return x*2 ... >>> give_me_twice = make_really_omg(5)(give_me_twice) «Подслащенный» >>> @make_really_omg(5) ... def give_me_twice(x): ... return x*2 ... 11
  12. 12. Дайте два! ● «снизу вверх» ● «изнутри наружу» ● Не очень красиво @usecase @render_to('usecase_research.html') @usecase_provider @rules.apply_(default_rules) def research_unit(request): ... usecase(render_to('usecase_research.html') (usecase_provider(rules.apply_(default_rules) (research_unit)))) 12
  13. 13. Рецепты 13
  14. 14. Декоратор — «вынесение общего знаменателя за скобки» По сути, пересмотр паттернов ООП для Python и реализация средствами декораторов. 14
  15. 15. Инфраструктура 15
  16. 16. Инфраструктура ● Изменяет окружение ● Не меняет функцию/аргументы (обычно) ● Примеры: ● @commit ● @cache ● Псевдокод >>> def infrastructure(func): ... def wrapper(*args, **kwargs): ... prepare_environ() ... res = func(*args, **kwargs) ... fix_environ() ... return res ... return wrapper 16
  17. 17. Интерфейс 17
  18. 18. Интерфейс ● Регистрация однородных объектов ● Проверка требований (опционально) ● Примеры: ● @register.tag (Django) ● Псевдокод >>> CALLBACKS = [] >>> def callback(func): ... def wrapper(*args, **kwargs): ... res = func(*args, **kwargs) ... assert res is not None ... return res ... CALLBACKS.append(wrapper) ... return wrapper 18
  19. 19. Адаптер 19
  20. 20. Адаптер ● Согласование API, преобразование данных ● Часто — фабрики ● Примеры: ● @render_to (Django, Александр Соловьев) ● @permalink (Django) ● Псевдокод >>> def render_to(template): ... def decor(view): ... def wrapper(request, *args, **kwargs): ... context = view(request, *args, **kwargs) ... return render(template, request, context) ... return wrapper ... return decor 20
  21. 21. Гард 21
  22. 22. Гард ● Вынос типичного условного перехода ● Примеры: ● @login_required (Django) ● @validate (Pylons) ● Псевдокод >>> def login_required(view): ... def wrapper(request, *args, **kwargs): ... if request.user.is_authenticated(): ... return view(request, *args, **kwargs) ... else: ... return HttpResponseForbidden() ... return wrapper 22
  23. 23. Реальная жизнь - ajax_request def ajax_request(func): def wrapper(request, *args, **kwargs): гард if request.method == 'POST': response = func(request, *args, **kwargs) else: response = { 'error': { 'type': 405, 'message': 'Accepts POST only' } } адаптер if isinstance(response, dict): resp = JsonResponse(response) if 'error' in response: resp.status_code = response['error'].get('type', 500) return resp return response return functools.wraps(func)(wrapper) http://is.gd/7h6H7 23
  24. 24. Реальная жизнь - reg.simple_tag def simple_tag(self, func): params, xx, xxx, defaults = getargspec(func) class SimpleNode(Node): [...] адаптер compile_func = curry( generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode ) compile_func.__doc__ = func.__doc__ интерфейс self.tag( getattr(func, "_decorated_function", func).__name__, compile_func ) return func http://is.gd/7hdMu 24
  25. 25. Кунг-фу Это к Сергею Щетинину ;) http://self.maluke.com/ 25
  26. 26. P.S. Ссылки ● http://www.siafoo.net/article/68 ● http://pypi.python.org/pypi/decorator ● http://tinyurl.com/decorator-guard 26
  27. 27. Спасибо за внимание Вопросы? 27

×