Your SlideShare is downloading. ×
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Decorators' recipes
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Decorators' recipes

1,357

Published on

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

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,357
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
21
Comments
0
Likes
2
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Рецепты декораторов Юрий Юревич yury.yurevich@equelli.com | http://pyobject.ru PyCamp Kyiv, Киев, 2010. 1
  • 2. О докладчике ● Живу от Киева >2000 км ● В области разработки ПО >7 лет ● С Python >5 лет ● Блог о Python >3 лет ● Конференция по Ruby&Python >2 лет 2
  • 3. О докладе ● Ингредиенты ● Функция — объект первого рода ● Декоратор — обёртка ● Синтаксический сахар ● Рецепты ● Инфраструктура ● Интерфейс ● Адаптер ● Гард ● Примеры из реальной жизни 3
  • 4. Ингредиенты 4
  • 5. Ингредиенты (2) Декоратор = функции(объекты первого рода) + вложенные функции + @синтаксический_сахар 5
  • 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. Декоратор — обёртка функции >>> 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. Вложенные функции >>> 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. Фабрика! >>> 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. Еще и классы >>> 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. Синтаксический сахар @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. Дайте два! ● «снизу вверх» ● «изнутри наружу» ● Не очень красиво @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
  • 14. Декоратор — «вынесение общего знаменателя за скобки» По сути, пересмотр паттернов ООП для Python и реализация средствами декораторов. 14
  • 15. Инфраструктура 15
  • 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
  • 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
  • 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
  • 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. Реальная жизнь - 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. Реальная жизнь - 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. Кунг-фу Это к Сергею Щетинину ;) http://self.maluke.com/ 25
  • 26. P.S. Ссылки ● http://www.siafoo.net/article/68 ● http://pypi.python.org/pypi/decorator ● http://tinyurl.com/decorator-guard 26
  • 27. Спасибо за внимание Вопросы? 27

×