Как стать автором
Обновить

Комментарии 38

спасибо. ждем вторую часть
Присоединяюсь.
Что в декораторах такого волшебного и непостижимого, заставляющего писать очередной пост про них?
Для людей, давно и серьёзно занимающихся программированием — почти ничего.
Для новичков, как показывает практика, эта тема неочевидна.

Плюс, во второй части будет больше неочевидных вещей, таких как: фабрики декораторов, декораторы с параметрами, декораторы для методов и т.д.

Надеюсь, наличие данного материала на русском никому не повредит:)
Я больше скажу. Некоторым еще и полезна будет.
Напишите, если не трудно про y-комбинатор, а то статья на хабре просто мне мозг выломала( хотя там строчек кода штук 5 на пример). Так полностью и не понял.
НЛО прилетело и опубликовало эту надпись здесь
Y-комбинатор позволяет в анонимной функции использовать рекурсию с использованием самой себя, без необходимости назначения ей имени — функция остаётся анонимной.

Скажем, у нас есть неанонимная рекурсивная функция вычисления факториала:
def fact(n):
    return n * fact(n-1) if n > 0 else 1
print fact(10)

Это работает, т.к. у нашей функции есть имя fact и мы можем по нему функцию вызывать внутри неё самой.

Но если мы захотим написать анонимную функцию вычисления факториала, мы столкнемся с проблемой — как нам внутри функции вызвать её саму, не имея имени.
Можно попробовать сделать так:
fact = lambda self, n: n * self(self, n) if n > 0 else 1
print fact(fact, 10)

В данном случае имя функции не встречается внутри неё. Но при внешнем вызове функции приходится передавать в качестве одного из аргументов ссылку на неё саму. Это можно обернуть так:
wrap = lambda fn, *args: fn(fn, *args)
fact = lambda self, n: n * self(self, n) if n > 0 else 1
print wrap(fact, 10)

Теперь мы её ещё немного дообернем:
y = lambda fn: lambda *args: fn(fn, *args)
fact = y(lambda self, n: n * self(self, n) if n > 0 else 1)

Вот y и есть Y-комбинатор, к тому же анонимный. Пользуем inline как то так:
# применяем анонимную рекурсивную функцию
map(
    (lambda fn: lambda *args: fn(fn, *args))(
        lambda self, n: n * self(self, n-1) if n > 0 else 1),
    [1,2,3]
)

PROFIT! :)
Видимо тем, что остальные статьи заканчивались на первом примере этого поста.
Иными словами автор выбрал несколько иной подход, сперва привел итоговый пример, а затем разложил все по полочкам, так сказать сохранил интригу и не дал заснуть.
Что в декораторах такого волшебного и непостижимого, заставляющего писать очередной пост про них?
Для человека, издревле работающего с питоно-подобными языками ничего.

А вот программера, взрощенного на светлых идеалах паскале- и си-подобных языков, поначалу несколько обескураживает фраза «каждая функция есть объект». А последующее знакомство с теми же декораторами вообще вводит в некоторое замешательство, требующее осознания и последующей перестройки некоторых принципов, укрепившихся в мозге. Вот тут-то подобные статьи и оказываются очень кстати.
Ведь чем более разнообразным количеством слов и статей будет описана некая сущность, тем проще её разложить по полочкам и осознать.
На Си всё не так плохо, если не требуется метапрограммирование и прочий манкипатчинг. Указатели на функцию в данном контексте являются практическим полным аналогом ссылки на объект Function — можно присваивать переменным, можно вызывать из переменной, можно передавать в другие функции, а значит можно использовать паттерн «декоратор».

хаскель-барби смотрит на питоновцев и точно также (только с большими глазами) недоумевает — чего такого волшебного в монадах, что о них пишет какждый, освоивший хаскель и умеющий писать.
В статье не упоминается что декораторы могут быть применены не только к функциям, но и к целым классам! Таким образом они могут управлять вызовами классаов с целью создания экземпляров, и самими объектами классов, например добавлять новые методы в классы.
так же нет инфы что декораторы могут вызываться с аргументами
Если бы вы посмотрели по ссылке на оригинал, то заметили бы, что после данного материала идёт как раз «Passing arguments to the decorated function» («Передаем аргументы декорируемым функциям») и «Decorating methods» («Декорируем методы»). Вызов декораторов с параметрами так-же будет во второй части, как я успел упомянуть в этом комментарии.

Резюмируя: не спешите, всё будет:)

И спасибо за критику!
habrahabr.ru/post/74838/
habrahabr.ru/post/46306/
habrahabr.ru/post/86255/
habrahabr.ru/post/139866/
Вот ей богу не надоело еще ??? Мне даже кармы не жалко — но… прям ррр… Я сам php разработчик, начал недавно изучать python. Так вот в питоне куча всего интересного, помимо декораторов. И ими начинающие вряд ли со старта пользоваться будут, а если будут то еще быстрее запутаются (особенно полезен совет вложить декоратор в декоратор — вордпрес напоминает 2 версии, там не декораторы но пол движка на хуках...).
Одновременное использование нескольких версий на одной машине (linux), параллельные вычисление, отладка кода, оптимизация, подсчет занимаемой памяти и куча всего всего — довольно ж сильный язык жеж? Что мусолить одну тему по 10 раз?
Спасибо за комментарий!

Попробую ответить на всё.

habrahabr.ru/post/74838/
habrahabr.ru/post/46306/
habrahabr.ru/post/86255/
habrahabr.ru/post/139866/

1. На Хабре ≈140000 статей, не удивительно, что есть статьи по схожим темам. Уверяю вас, перед тем, как браться за перевод я поискал материалы по данной теме на Хабре и, по моему мнению, тот, что перевожу я, не является дублирующим в целом.

ими начинающие вряд ли со старта пользоваться будут, а если будут то еще быстрее запутаются

2. Со старта — не будут. Но когда-нибудь ведь начнут:)

особенно полезен совет вложить декоратор в декоратор

3. В данной статье нету советов, лишь описание того, как это работает.

Что мусолить одну тему по 10 раз?

4. Надеюсь, вторая часть Вам покажется более «незамусоленой».
Отличная статья, спасибо! Просто и понятно.
У меня есть вопрос, возможно глупый, но все же:
зачем разработчики python сделали что функция-декоратор возвращает функцию-обёртку, которая затем вызывается? Как мне это можно было сделать следующим образом: когда вызывается декорированная функция, вместо нее просто вызывается функция-декоратор, который получает первым аргументом данную функцию.

Демонстрация кодом:

def decorator ():


@ decorator
def func ():


Сейчас сделано так:

decorator (func) ()

Мой вариант:

decorator (func)

Я не говорю что мой вариант лучше.
Потому что func без скобок возвращает объект Function. Если мы декорируем его, то тип возврата не должен изменяться, декорация должна быть прозрачной для вызывающего кода. Везде где используется func, должна использоваться и decorator(func). Например, вложенные декораторы — как вы в своем варианте их реализуете?
Ваш вариант сработает для декораторов простейших функций.
Но, предположим, Вам нужно декорировать такую ф-ию:
def func(var):
    print "I've got", var


Тогда, вызвав
 decorator(func)("10$")
мы получим ожидаемое поведение.
В случае
 decorator(func)
нам просто «некуда» передать аргумент (как пробрасывать аргументы через декоратор — в скором времени будет показано).

Надеюсь, я верно понял суть Вашего вопроса?:)
# Возьмём функцию и запишем её в переменную
talk = getTalk()


Скобки же не нужны?
Функция getTalk возвращает другую функцию.
что-за редактор, шрифт, тема на скрине?
Sublime Text 2
Теперь мы знаем, что функции являются полноправными объектами

Из ваших примеров этого не следует. В своих примерах вы лишь показываете, что в питоне есть функции высшего порядка. Они, например, есть и в php, но, тем не менее, в php функция не является объектами.
А еще там есть отличные ответы этого же человека про итераторы и метаклассы. Непонятно только, зачем все это переводить в бесконечном количестве. Все подобные хорошие посты в первых 2-3 ссылках по запросам в поисковике.
Да, всё действительно так просто! @decorator — просто синтаксический сахар для конструкций вида:
Декораторы — это просто pythonic-реализация паттерна проектирования «Декоратор».
второе утверждение не верное. пруф.

конечно, это перевод и придирка относится к оригинальному тексту.
«вы можете назначить её переменнной», «помещаем в переменную», «записаны в переменную»
Есть хороший термин «связать с перменной», без риска свалиться в вопросы — где располагается то место в которое что-то помещается, сколько места занимает ссылка на объект, итп.

Спасибо, тоже резал глаз этот момент, но про связку забыл.:)
Fixed
«раз мы можем возвращать функцию, значит, мы можем и передавать её другой функции, как параметр»
Это два разных явления, являющимися следствиями того, что функции являются объектами «первого класса».
НЛО прилетело и опубликовало эту надпись здесь
великолепный пример с седвичем.
Просто отличная оригинальная статья и замечательный ее перевод! Спасибо огромное. Самый приятный, нескучный и понятный стиль объяснения.
Спасибо огромное самое вменяемое объяснение.

А как завернуть декоратор, начинающийся с собаки @ в if ?
На сколько я понимамю, декоратор работает только без отступов от начала строки.

В питоне всё есть объект. Думайте о декораторе как об обычном decorator(func), и если надо используйте хоть в if, хоть где-либо ещё. Единственное что, ветвление if будет оценивать булевый тип.

Спасибо автору за статью и за то, что она оказалась не такой длинной, как он обещал)

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории