Подтвердить что ты не робот

Макросы Python: используйте случаи?

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

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

4b9b3361

Ответ 1

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

  • ITERATE, который является забавным и расширяемым контуром цикла
  • CL-YACC/FUCC, которые генераторы парсеров, которые генерируют парсеры во время компиляции
  • CL-WHO, который позволяет указывать html-документы со статическими и динамическими частями.
  • Parenscript, который является генератором кода javascript
  • Различные простые обертки кода, например обработчики ошибок (у меня есть обработчик ошибок с gtk-error-message, который выполняет код и показывает GtkMessageDialog, если возникает необработанная ошибка), исполнители (например, с учетом кода, выполняют его в разных thread; у меня есть макрос внутри основного потока, который выполняет код в разных потоках; PCall библиотека использует макросы для переноса кода, который будет выполняться одновременно )
  • Создатели GUI с макросами (например, задают свойства иерархии виджета и виджеты и имеют макрос, генерирующий код для создания всех виджетов)
  • Генераторы кодов, которые используют внешние ресурсы во время компиляции. Например, макрос, который обрабатывает заголовки C и генерирует код FFI или макрос, который генерирует определения классов на основе схемы базы данных.
  • Декларативная FFI. Например, указывая внешние структуры, функции, их типы аргументов и имеющие макросы для создания соответствующих структур lisp, функций с отображением типов и кода маршалинга
  • Основанные на непрерывности веб-фреймворки для Common lisp используют макросы, которые преобразуют код в форму CPS (продолжение).

Ответ 2

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

Макросы неотъемлемо неписаны.

Ответ 3

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

@case
class Point(x, y)

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

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

  • Классы классов, легко Алгебраические типы данных из Scala
  • Соответствие шаблону из мира функционального программирования
  • Оптимизация вызовов по времени
  • Quasiquotes - быстрый способ манипулирования фрагментами программы.
  • String Interpolation, общая функция на многих языках и Pyxl.
  • Отслеживание и Smart Asserts
  • PINQ to SQLAlchemy, клон LINQ to SQL с С#
  • Быстрый Lambdas от Scala и Groovy,
  • Комбинированные компоненты Parser, вдохновленные Scala.

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

Ответ 4

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

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

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

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

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

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

Ответ 6

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

Это пример из неполного лучеискателя, написанного в clojure:

(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]
       [email protected])))

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

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

Это невозможно обойтись без макросов, потому что @body может означать что угодно внутри (для пикселя я j @body)

Что-то вроде этого было бы возможно и в python. Вам нужно использовать декораторы. Вы не можете делать все, что можете, с макросами lisp, но они очень мощные

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

Ответ 9

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

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

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

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

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

Ответ 10

Прочитайте "Лямбда-документы", чтобы вы могли узнать, почему вообще можно было бы напасть на макросы.

Вы должны начать с "AIM-353 Lambda: The Ultimate Imperative и следовать за ним с помощью AIM-443 Lambda: The Ultimate GOTO. Оба они могут быть найдены здесь:

http://library.readscheme.org/page1.html

Ответ 11

Hy, Для моего собственного использования я создал модуль Python (Espy), который позволяет определять макросы с помощью аргументов, генерации цикла и условного кода: Вы создаете файл source.espy, затем запускаете соответствующую функцию, затем генерируется source.py.

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

macro repeat(arg1):
    for i in range(%arg1%):
        socket
    print "stop"
   ...
repeat(5):
    print "Hi everybody"
    print "See you soon"

эквивалентно:

...
for i in range(5):
    print "Hi everybody"
    print "See you soon"
print "stop"

Другой синтаксис:

macro doit(arg1):
    for i in %arg1%:
        socket suit(arg2):
            socket
            print %arg2%
        socket check(arg3):
            if %arg2%==%arg3%:
                socket
...
#use
doit(range(10)):
    suit(result):
        result=i*i
    check(result,25):
        print "I knew that 5*5 == 25"

эквивалентно:

for i in range(10):
    result=i*i
    print result
    if result==25:
        print "I knew that 5*5 == 25"

Дополнительно, Espy имеет 2 функции: "macro for" и "macro if". Пример:

macro for v in [6,10,12,20,23]:
    macro if 7<%v%<22:
        True:
            print "At %v%, I'm awake."
        False:
            print "At %v%, I'm sleeping."

переводится Espy в:

print "At 6, I'm sleeping."
print "At 10, I'm awake."
print "At 12, I'm awake."
print "At 20, I'm awake."
print "At 23, I'm sleeping."

Полная документация и бесплатная загрузка можно найти здесь: http://elp.chronocv.fr

Я использую этот модуль во многих случаях. Он позволяет создавать более структурированные и более короткие коды. С его помощью я создал 65000 строк четкого и эффективного кода python из 1000 строк кода espy для нового проекта шахматного движка (все еще продолжается).

Если Python может включать макросы в выпуске futur, это станет более впечатляющим.

Ответ 12

Я бы использовал его для переноса yield, чтобы я мог создавать более мощные конвейеры генераторов.

Ответ 13

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

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

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

PEP в стороне, мне также понравится макрос unless. Вместо написания:

if not is_superman():
    dodge_bullet()

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

unless is_superman():
    dodge_bullet()

Мне нужен макрос case (часто называемый cond в Lisp). Вместо написания:

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 самого интерпретатора.)

Ответ 14

Возможно, если вы хотите использовать исходный код во время выполнения, например, для отладки (скажем, printf отлаживает значение выражения с его именем, поэтому вам не нужно писать его дважды).

Единственный способ, которым я мог бы это сделать в python, - передать строку в eval.

Ответ 15

Ну, я бы хотел вместо

print >> sys.stderr, "abc"

написать

err "abc"

в некоторых сценариях, которые содержат много отладочных инструкций распечатки.

Я могу сделать

import sys
err = sys.stderr

а затем

print >> err, "abc"

который короче, но на линии все еще занимает слишком много символов.

Ответ 16

Я хочу использовать макрос, чтобы включить sql-оператор в код python. - выберите * из таблицы1

Ответ 17

Исходя из C-мира, я бы очень признателен за то, что вы умеете эффективно регистрировать богатые сообщения. Вместо написания

if logger.level > logger.DEBUG:
    logger.log('%s' % (an_expensive_call_that_gives_useful_info(),))

с макросами, можно вместо этого сделать что-то вроде

DEBUG('%s' % (an_expensive_call_that_gives_useful_info(),))