Pull to refresh

Comments 30

теперь можете перенести в блог Python :-)
почему это не имеет ничего общего с паттерном? похоже, что это он и есть. в современной литературе его еще называют AOP-подходом

и почему в статье нет примеров или даже перечисления реального использования декораторов? книжные примеры «посчитать время выполнения функции» совсем не дают понятия, как их можно использовать в реальной жизни
к сожалению, декораторы — это весьма условная реализация АОР. очень условная, к тому же смешивающая Advices и PoI.
а на счет примеров — так приведите несколько хороших, все были бы благодарны
Из примеров реального использования декораторов можно было бы привести примр декоратора @login_required из Django.
примеры (первое, что приходит в голову) —
— проверка прав текущего пользователя для выполнения функции
— прозрачная работа с транзакциями БД (commit, rollback)
— кеширование результатов выполнения функции
>— прозрачная работа с транзакциями БД (commit, rollback)

Для этого есть with и контексты, они гораздо лучше справляются с этой работой. Но это уже придирки с моей стороны. Подобных примеров можно найти десятки, они ничуть не лучше уже приведённых. Хотя, конечно, можно привести в качестве иллюстрации. Но повторюсь, они не добавляют бо́льшего понимания, относительно уже приведённых примеров.
Сходство весьма поверхностное. С таким же успехом можно было сравнивать с простой суперпозицией функций во время вызова. Адекватная реализация этого паттерна в питоне смотрится как-то чужеродно, впрочем, как и реализация практически любого объектно-классового паттерна. Но это уже тема отдельной дискуссии и огромного флейма на тему ООП vs. ФП.

«Посчитать время выполнения функции» — это отличный пример, отлично поясняющий суть декораторов. Аналогично с классом Thread. Другие примеры, например, с PyQt и декорированными обработчиками сигналов, используют вещи, далеко не всем знакомые и требующими кучи вводного текста.

Декораторы действительно сильно напоминают AOP, но проблема в том, что связывание декоратора с функцией происходит в момент прохода интерпретатором непосредственно определения функции. Это как минимум одна проблема. Для AOP мне показалось проще использовать тот же aspect.py, чем заморачиваться с декораторами.
Присоединяюсь к благодарности, загорелся желанием познакомиться с питоном. ;-)
Да, спасибо. Добавил ссылку. Код пока не могу добавить, так как живьём ещё «не щупал».
Интересно, единственное применение, котрое мне приходит в голову — это добавление доп. методов. А это проще делать наследованием. Где полезно применять декораторы классов?
Наследование не везде подходит, у тех же GOF в вводных главах («Наследование и композиция») этот вопрос рассматривается. Правда, там есть неявные завязки на природу C++ и прочих подобных языков. К сожалению, не могу скопипастить, так как под рукой только бумажная книга.
Фразы «В самом начале хочется отметить, что рассматриваемый здесь декоратор (decorator) как элемент языка Python не имеет никакого отношения к одноимённому паттерну проектирования.» хватает чтобы не читать дальше. Или вы в самом паттерне не разобрались или в его реализации на Питоне.

Почитайте Еккеля
www.artima.com/weblogs/viewpost.jsp?thread=240808
www.artima.com/weblogs/viewpost.jsp?thread=240845
www.artima.com/weblogs/viewpost.jsp?thread=241209

www.mindviewinc.com/Books/Python3Patterns/Index.php
он всё таки более основательно к написанию статтей подходит.
Открываю GOF.
«Назначение: Динамически добавляет объекту новые обязаности. Является гибкой альтернативой порожению подкласов с целью расширения функциональности». Что не так с питоновским декоратором и чем он не отвечает определению?
Еккель — джавист, его т.н. «книга» Python 3 Patterns является попыткой навязать джавовский классовый подход к питону, а это неправильно. Посмотрим, во что она в итоге выльется, но пока отношение к ней у меня сугубо негативное.

Теперь к теме вопроса. Паттерн Декоратор имеет весьма условное отношение к одноимённой концепции из питона, а именно — питоновский декоратор может использоваться для реализации паттерна, но это очень небольшая часть, для чего он может использоваться. С таким подходом банальную суперпозицию фукций можно тоже объявить реализацией паттерна. Схожесть концепций не более чем схожесть. Наверное, процитированное утверждение может показаться слишком категоричным, я его исправлю.
Прочитайте пожалуйста wiki.python.org/moin/PythonDecorators. И На питоновской вики чётко указывается: «This supports more readable applications of the DecoratorPattern but also other uses as well.» то есть в ПЕРВУЮ очередь синтаксический сахар для реализации паттерна, но можно использовать и для других вещей. Конкретная реализация более мощная, но уже само название указывает первоначальное предназначение.

Именно ваша категоричность указывает либо непонимание либо нежелание принять действительность и навязать собственное видение. Не нравится АОП, но декораторы тут причём? АОП начали продвигать где-то в 2004-м. GOF вышла в 1995-м.
Новичёк открывает раздел на хабрахабре Питоновкую вики и видит такое утверждение и потом всюду будет приводить его как истину, тогда либо пишите статью для професионалов с изложением теоретических и практических концепций декорирования и вашей обоснованой или нет критикой, а вводные статьи таких утвеждений иметь не должны, потому как запутывают.
Да, я понял вашу мысль, впредь постараюсь быть поаккуратнее в формулировках.
Таки прочитал топик: «Indeed, you can use Python decorators to implement the Decorator pattern, but that's an extremely limited use of it. Python decorators, I think, are best equated to macros.» Примерно это я и имел в виду, практически дословно получилось :)
Для того чтобы не ломалось ни __doc__ ни имя функции используйте functools.wraps
По-моему, в примере с классом Thread лучше реализовать декоратор так, чтобы функцию можно было вызывать традиционным способом, а не используя метод start(). Вроде так:
import threading

class Thread(threading.Thread):
    def __init__(self, f):
        threading.Thread.__init__(self)
        self.run = f
    def __call__(self):
        return self.start()

@Thread
def ttt():
    print "This is a thread function"

ttt()
Но глава о декораторах уже написана :)
И уже откритикована, в том числе и ван Россумом. Эккель навязывает «классовый» подход, но явно об этом факте не упоминает, возможно, в финальной редакции книги это будет указано.
Да, я читал, но мне что-то не понравилось. Он и сам признается, что Питон пока не очень хорошо знает. По Яве книжку замечательно написал, слов нет. Будем ждать то же самое по Питону.
Вот это интересно. Человек, написавший книгу по питону, признаётся, что не очень хорошо знает питон.
Не написавший, а пишущий. В этом нет ничего удивительного. Так же зачастую мы начинаем писать программу на языке, которого не знаем. К тому же Эккель, как человек, написавший «Философию Java» вполне достоин доверия.
Хорошая статья, только я бы избегал использования жаргона:
референс = ссылка
инстанс = экземпляр
актуальный = действительный
Only those users with full accounts are able to leave comments. Log in, please.