Макросы Python: случаи использования? - PullRequest
20 голосов
/ 19 апреля 2009

Если бы в Python был макрос, похожий на Lisp / Scheme (что-то вроде MetaPython ), как бы вы его использовали?

Если вы программист на Лисп / Схеме, для каких вещей вы используете макросы (кроме тех, которые имеют четкую синтаксическую параллель в Python, например цикл while)?

Ответы [ 17 ]

15 голосов
/ 19 апреля 2009

Я считаю, что макросы противоречат культуре Python. Макросы в Лиспе позволяют большой шарик грязи ; Вы можете переопределить язык, чтобы он стал более подходящим для вашей проблемной области. И наоборот, Pythonic код использует наиболее естественную встроенную функцию Python для решения проблемы, вместо того, чтобы решать ее более естественным образом на другом языке.

Макросы по своей сути не пифоничны.

13 голосов
/ 11 мая 2013

Это несколько поздний ответ, но MacroPy - мой новый проект по переносу макросов в Python. У нас есть довольно обширный список демонстраций, каждый из которых является сценарием использования, для реализации которого требуется макрос, например, предоставляя чрезвычайно сжатый способ объявления классов:

@case
class Point(x, y)

p = Point(1, 2)
print p.x   # 1
print p     # Point(1, 2)

MacroPy используется для реализации таких функций, как:

  • Классы дел, простые Алгебраические типы данных из Scala
  • Сопоставление с образцом из мира функционального программирования
  • Оптимизация Tail-Call
  • Квазицитаты, быстрый способ манипулирования фрагментами программы
  • Строковая интерполяция, общая черта многих языков и Pyxl.
  • Трассировка и интеллектуальные утверждения
  • PINQ к SQLAlchemy, клон LINQ to SQL из C #
  • Быстрые лямбды из Скалы и Groovy,
  • Parser Combinators, вдохновленные Scala's .

Проверьте ссылку на страницу, чтобы узнать больше; Я думаю, что могу с уверенностью сказать, что примеры использования, которые мы демонстрируем, намного превосходят все, что кто-либо предлагал в этой теме = D

12 голосов
/ 19 апреля 2009

Некоторые примеры макросов lisp:

  • ITERATE , забавный и расширяемый цикл
  • CL-YACC / FUCC , которые являются генераторами парсеров, которые генерируют парсеры во время компиляции
  • CL-WHO , позволяющий указывать HTML-документы со статическими и динамическими частями
  • Parenscript , который является генератором кода JavaScript
  • Различные простые обертки кода, например, обработчики ошибок (у меня есть with-gtk-error-message-handler, который выполняет код и показывает GtkMessageDialog, если происходит необработанная ошибка), исполнители (например, с учетом кода, выполняют его в разных у меня есть макрос внутри основного потока, который выполняет код в разных потоках; библиотека PCall использует макросы для переноса кода, выполняемого одновременно)
  • GUI-компоновщики с макросами (например, указать иерархию виджетов и свойства виджетов и иметь макрос для генерации кода для создания всех виджетов)
  • Генераторы кода, которые используют внешние ресурсы во время компиляции. Например, макрос, который обрабатывает заголовки C и генерирует код FFI, или макрос, который генерирует определения классов на основе схемы базы данных
  • Декларативная ФФИ. Например, указание сторонних структур, функций, типов их аргументов и наличие макросов для генерации соответствующих структур lisp, функций с отображением типов и кодом маршалинга
  • Веб-фреймворки, основанные на продолжениях, для Common Lisp используют макросы, которые преобразуют код в форму CPS (стиль передачи продолжения).
6 голосов
/ 15 марта 2010

Вот один пример из реальной жизни, с которым я столкнулся, который был бы тривиален с макросами или реальной поддержкой метапрограммирования, но должен быть сделан с манипуляциями с байт-кодом CPython из-за отсутствия обоих в Python:

http://www.aminus.net/dejavu/chrome/common/doc/2.0a/html/intro.html#cpython

Вот как эта проблема решается в Common Lisp с использованием комбинации регулярных макросов и read-макросов для расширения синтаксиса (это можно было бы сделать без последнего, но не первого):

http://clsql.b9.com/manual/csql-find.html

Та же проблема, решаемая в Smalltalk с использованием замыканий и метапрограммирования (Smalltalk - один из немногих ОО-языков с одной диспетчеризацией, который действительно правильно передает сообщения):

http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg02096.html

Здесь я попытался реализовать подход Smalltalk в Common Lisp, который является хорошей иллюстрацией того, как метапрограммирование плохо поддерживается в последнем:

http://carcaddar.blogspot.com/2009/04/closure-oriented-metaprogramming-via.html

5 голосов
/ 19 апреля 2009

В lisp макросы - это просто еще один способ абстрагировать идеи.

Это пример неполного трассировщика лучей, написанного в ближайшем будущем:

(defmacro per-pixel
  "Macro.
Excecutes body for every pixel. Binds i and j to the current pixel coord."
  [i j & body]
  `(dotimes [~i @width]
     (dotimes [~j @height]
       ~@body)))

Если вы хотите сделать что-то для каждого пикселя с координатами (i, j), скажем, нарисовать черный пиксель, если я четный, вы должны написать:

(per-pixel i,j
  (if (even? i)
    (draw-black i,j)))

Невозможно обойтись без макросов, потому что @body может означать что-либо внутри (на пиксель i j @body)

Нечто подобное было бы возможно и в python. Вам нужно использовать декораторы. Вы не можете делать все, что можете делать с макросами LISP, но они очень мощные

Ознакомьтесь с этим уроком по оформлению: http://www.artima.com/weblogs/viewpost.jsp?thread=240808

4 голосов
/ 19 апреля 2009

Существует список рассылки ( archive.org mirror ), который довольно хорошо это объясняет. Пост о Perl, но он также применим и к Python.

3 голосов
/ 19 апреля 2009

Некоторые случаи использования, которые я видел ранее, включают создание фабрик классов или извлечение логирования операторов из производственного кода.

2 голосов
/ 19 апреля 2009

Я не думаю, что Python нужны макросы, потому что они полезны для 2 вещей:

  1. Создание DSL или более красноречивого синтаксиса для чего-либо (хороший пример - макрос LISP LISP). В этом случае философия Python сознательно отказалась от этого. Если вы пропустили какое-то явное обозначение, вы всегда можете попросить PEP.

  2. Делаем вещи быстрее, предварительно вычисляя их во время компиляции. Python не ориентирован на скорость, поэтому вы всегда можете использовать функцию.

Я не говорю, что макросы неправильны, просто они не соответствуют философии Python. Вы всегда можете обойтись без них без большого дублирования кода, потому что у вас есть утка, набирающая текст и перегрузка операторов.

И в качестве примечания я бы предпочел увидеть перезапуски Lisp в Python, чем макросы.

2 голосов
/ 19 апреля 2009

См. Также этот вопрос: Синтаксис Pythonic macro

1 голос
/ 23 апреля 2013

В настоящее время единственным способом, которым можно добавить функции в Python, является использование PEP (Python Enhancement Proposal). Это может быть медленным и не поможет вам в тех случаях, когда вы хотите добавить к языку функцию, полезную только для вашего варианта использования.

Например, есть PEP для добавления цикла do-while . Это, вероятно, будет добавлено в Python, но PEP был создан в 2003 году. Сегодня я хотел бы написать циклы do-while, и я мог бы сделать это, если бы в Python были макросы.

Аналогично, был PEP, чтобы добавить помеченный разрыв и продолжить , но это было отклонено. Если помеченные операторы break сделают мой код более понятным, я могу реализовать их с помощью макроса.

PEPs в стороне, я также хотел бы макрос unless. Вместо того чтобы писать:

if not is_superman():
    dodge_bullet()

Я мог бы написать:

unless is_superman():
    dodge_bullet()

Я бы хотел макрос case (часто называемый cond в Лиспе). Вместо того чтобы писать:

if x == FOO:
    do_stuff_with_foos()
elif x == BAR:
    do_stuff_with_bars()
elif x == BAZ:
    do_stuff_with_bazs()

Я мог бы написать:

switch x:
   case FOO:
       do_stuff_with_foos()
   case BAR:
       do_stuff_with_bars()
   case BAZ:
       do_stuff_with_bazs()

Это было бы просто реализовать в виде макросов. Более сложные полезные макросы будут включать:

  • Интерполяция строк в стиле Ruby, например "hello there {user}" (вероятно, лучше всего реализовано как макрос для чтения)
  • Сопоставление с образцом

В настоящее время это только функции на других языках. С помощью макросов я мог бы добавить их в Python. Я мог бы даже написать PEP, которые включали пример реализации. (Некоторые PEP уже делают это, но они вынуждены изменить источник C самого интерпретатора.)

...