Date post: | 16-Jun-2015 |
Category: |
Technology |
Upload: | yury-yurevich |
View: | 1,390 times |
Download: | 4 times |
2
О докладчике
● Живу от Киева >2000 км● В области разработки ПО >7 лет● С Python >5 лет● Блог о Python >3 лет● Конференция по Ruby&Python >2 лет
3
О докладе
● Ингредиенты● Функция — объект первого рода● Декоратор — обёртка● Синтаксический сахар
● Рецепты● Инфраструктура● Интерфейс● Адаптер● Гард
● Примеры из реальной жизни
4
Ингредиенты
5
Ингредиенты (2)
Декоратор = функции(объекты первого рода) + вложенные функции + @синтаксический_сахар
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)
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)
декоратор
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>
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>
10
Еще и классы
>>> def make_really_strange(func):... def wrapper(z):... res = func(z + 2)... return res... return wrapper
>>> class make_really_strange(object):... def __init__(self, func):... self.func = func... def __call__(self, z):... res = self.func(z + 2)... return res
func → wrapper
func → <instance>
11
Синтаксический сахар
>>> def give_me_twice(x):... return x*2...
>>> give_me_twice = make_really_omg(5)(give_me_twice)
@name — неявный вызов name(func)
«Подслащенный»
«Обычный»
>>> @make_really_omg(5)... def give_me_twice(x):... return x*2...
12
Дайте два!
● «снизу вверх»● «изнутри наружу»● Не очень красиво@usecase@render_to('usecase_research.html')@[email protected]_(default_rules)def research_unit(request): ...
usecase(render_to('usecase_research.html')(usecase_provider(rules.apply_(default_rules)(research_unit))))
13
Рецепты
14
Декоратор — «вынесение общего
знаменателя за скобки»
По сути, пересмотр паттернов ООП для Pythonи реализация средствами декораторов.
15
Инфраструктура
16
Инфраструктура
● Изменяет окружение● Не меняет функцию/аргументы (обычно)● Примеры:
● @commit● @cache
● Псевдокод>>> def infrastructure(func):... def wrapper(*args, **kwargs):... prepare_environ()... res = func(*args, **kwargs)... fix_environ()... return res... return wrapper
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
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
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
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
24
Реальная жизнь - reg.simple_tagdef 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
26
P.S. Ссылки
● http://www.siafoo.net/article/68 ● http://pypi.python.org/pypi/decorator● http://tinyurl.com/decorator-guard
27
Спасибо за внимание
Вопросы?