При поиске декораторов Python кто-то утверждал, что они такие же мощные, как макросы Lisp (особенно Clojure).
Глядя на примеры, приведенные в PEP 318, мне кажется, что это всего лишь причудливый способ использования простых старых функций высшего порядка в Лиспе:
def attrs(**kwds):
def decorate(f):
for k in kwds:
setattr(f, k, kwds[k])
return f
return decorate
@attrs(versionadded="2.2",
author="Guido van Rossum")
def mymethod(f):
...
Я не видел никакого преобразования кода ни в одном из примеров, как описано в « Анатомии Clojure Macro» . Кроме того, отсутствие однородности Python может сделать невозможным преобразование кода.
Итак, как эти два сравниваются и можете ли вы сказать, что они примерно равны в том, что вы можете сделать? Доказательства, кажется, указывают на это.
Изменить: на основе комментария, я ищу две вещи: сравнение «так мощно, как» и «так легко делать удивительные вещи с».
Ответы:
Декоратор в основном только функция .
Пример в Common Lisp:
Выше функция является символом (который будет возвращен
DEFUN
), и мы помещаем атрибуты в список свойств символа .Теперь мы можем написать это вокруг определения функции:
Если мы хотим добавить необычный синтаксис, как в Python, мы напишем макрос для чтения . Макрос читателя позволяет нам программировать на уровне синтаксиса s-выражения:
Затем мы можем написать:
Читатель Lisp читает выше, чтобы:
Теперь у нас есть форма декораторов в Common Lisp.
Сочетание макросов и читательских макросов.
На самом деле я бы сделал перевод выше в реальном коде, используя макрос, а не функцию.
Использование, как указано выше, с тем же макросом читателя. Преимущество заключается в том, что компилятор Lisp по-прежнему рассматривает ее как так называемую форму верхнего уровня - файловый компилятор * обрабатывает формы верхнего уровня специально, например, добавляет информацию о них в среду времени компиляции . В приведенном выше примере мы видим, что макрос просматривает исходный код и извлекает имя.
Читатель Lisp читает приведенный выше пример в:
Который затем получает макрос, расширенный в:
Макросы очень отличаются от макросов читателя .
Макросы передают исходный код, могут делать что хотят, а затем возвращают исходный код. Входной источник не должен быть действительным кодом Lisp. Это может быть что угодно, и это может быть написано совершенно по-другому. Результат должен быть действительным кодом Lisp тогда. Но если сгенерированный код также использует макрос, то синтаксис кода, встроенного в вызов макроса, снова может быть другим синтаксисом. Простой пример: можно написать математический макрос, который будет принимать некоторый математический синтаксис:
Выражение
y = 3 x ^ 2 - 4 x + 3
не является допустимым кодом Lisp, но макрос может, например, проанализировать его и вернуть действительный код Lisp следующим образом:Есть много других случаев использования макросов в Лиспе.
источник
В Python (языке) декораторы не могут модифицировать функцию, только обернуть ее, поэтому они определенно гораздо менее мощны, чем макросы lisp.
В CPython (интерпретаторе) декораторы могут модифицировать функцию, потому что у них есть доступ к байт-коду, но функция компилируется в первую очередь, а затем может быть изменена декоратором, так что невозможно изменить синтаксис, вещь lisp-macro -эквивалент нужно было бы сделать.
Обратите внимание, что современные списки не используют S-выражения в качестве байт-кода, поэтому макросы, работающие со списками S-выражений, определенно работают до компиляции байт-кода, как отмечалось выше, в python декоратор запускается после него.
источник
Довольно сложно использовать Python-декораторы для внедрения новых механизмов управления потоком.
Использование макросов Common Lisp для внедрения новых механизмов управления потоком является тривиальным.
Из этого, вероятно, следует, что они не одинаково выразительны (я предпочитаю интерпретировать «мощный» как «выразительный», поскольку я думаю, что они на самом деле имеют в виду).
источник
s/quite hard/impossible/
Это, безусловно, связано с функциональностью, но из декоратора Python нетрудно изменить вызываемый метод (это будет
f
параметр в вашем примере). Чтобы изменить его, вы можете сойти с ума с модулем ast ), но вас может заинтересовать довольно сложное программирование.Тем не менее, все сделано в этом направлении: посмотрите на пакет macropy , чтобы найти несколько действительно изумительных примеров.
источник
ast
вещи -трансформирующие в python не равны макросам Lisp. В Python исходным языком должен быть Python, а в макросах Lisp исходным языком, преобразованным макросом, может быть буквально что угодно. Поэтому метапрограммирование Python подходит только для простых вещей (например, AoP), в то время как метапрограммирование Lisp полезно для реализации мощных компиляторов eDSL.