Python 宏:用例?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/764412/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:49:29  来源:igfitidea点击:

Python Macros: Use Cases?

pythonmacroslispscheme

提问by Rick Copeland

If Python had a macro facility similar to Lisp/Scheme (something like MetaPython), how would you use it?

如果 Python 有一个类似于 Lisp/Scheme(类似于MetaPython)的宏工具,你会如何使用它?

If you are a Lisp/Scheme programmer, what sorts of things do you use macros for (other than things that have a clear syntactic parallel in Python such as a while loop)?

如果您是 Lisp/Scheme 程序员,您将宏用于哪些用途(除了在 Python 中具有清晰语法并行的东西,例如 while 循环)?

采纳答案by dmitry_vk

Some examples of lisp macros:

lisp 宏的一些示例:

  • ITERATEwhich is a funny and extensible loop facility
  • CL-YACC/FUCCthat are parser generators that generate parsers at compile time
  • CL-WHOwhich allows specifying html documents with static and dynamic parts
  • Parenscriptwhich is a javascript code generator
  • Various simple code-wrappers, e.g., error handlers (I have a with-gtk-error-message-handler that executes code and shows GtkMessageDialog if unhandled error occurs), executors (e.g., given a code, execute it in different thread; I have a within-main-thread macro that executes code in different threads; PCalllibrary uses macros to wrap code to be executed concurrently)
  • GUI builders with macros (e.g., specify widgets hierarchy and widgets' properties and have a macro generate code for creation of all widgets)
  • Code generators that use external resources during compilation time. E.g., a macro that processes C headers and generates FFI code or a macro that generates classes definitions based on database schema
  • Declarative FFI. E.g., specifying the foreign structures, functions, their argument types and having macros to generate corresponding lisp structures, functions with type mapping and marshaling code
  • Continuations-based web frameworks for Common Lisp use macros that transform the code into CPS (continuation passing style) form.
  • ITERATE这是一个有趣且可扩展的循环工具
  • CL-YACC/ FUCC是在编译时生成解析器的解析器生成器
  • CL-WHO允许使用静态和动态部分指定 html 文档
  • Parenscript是一个 javascript 代码生成器
  • 各种简单的代码包装器,例如错误处理程序(我有一个 with-gtk-error-message-handler,它执行代码并在发生未处理的错误时显示 GtkMessageDialog)、执行程序(例如,给定代码,在不同的线程中执行它;我有一个在不同线程中执行代码的主线程内宏;PCall库使用宏来包装要并发执行的代码)
  • 具有宏的 GUI 构建器(例如,指定小部件层次结构和小部件的属性,并具有用于创建所有小部件的宏生成代码)
  • 在编译期间使用外部资源的代码生成器。例如,处理 C 头文件并生成 FFI 代码的宏或基于数据库模式生成类定义的宏
  • 声明性 FFI。例如,指定外部结构、函数、它们的参数类型并使用宏来生成相应的 lisp 结构、具有类型映射和封送代码的函数
  • Common Lisp 的基于延续的 Web 框架使用宏将代码转换为 CPS(延续传递风格)形式。

回答by RossFabricant

I believe that macros run counter to Python's culture. Macros in Lisp allow the big ball of mudapproach; you get to redefine the language to become more suited to your problem domain. Conversely Pythonic code uses the most natural built in feature of Python to solve a problem, instead of solving it in a way that would be more natural in a different language.

我相信宏与 Python 的文化背道而驰。Lisp 中的宏允许大泥球接近;您可以重新定义语言以使其更适合您的问题领域。相反,Pythonic 代码使用 Python 最自然的内置特性来解决问题,而不是以在不同语言中更自然的方式来解决问题。

Macros are inherently unpythonic.

宏本质上是非pythonic的。

回答by Li Haoyi

This is a somewhat late answer, but MacroPyis a new project of mine to bring macros to Python. We have a pretty substantial list of demos, all of which are use cases which require macros to implement, for example providing an extremely concise way of declaring classes:

这是一个有点晚的答案,但MacroPy是我的一个新项目,它将宏引入 Python。我们有一个非常丰富的演示列表,所有这些都是需要宏来实现的用例,例如提供了一种非常简洁的类声明方式:

@case
class Point(x, y)

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

MacroPy has been used to implement features such as:

MacroPy 已被用于实现以下功能:

  • Case Classes, easy Algebraic Data Typesfrom Scala
  • Pattern Matching from the Functional Programming world
  • Tail-call Optimization
  • Quasiquotes, a quick way to manipulate fragments of a program
  • String Interpolation, a common feature in many languages, and Pyxl.
  • Tracing and Smart Asserts
  • PINQ to SQLAlchemy, a clone of LINQ to SQL from C#
  • Quick Lambdas from Scala and Groovy,
  • Parser Combinators, inspired by Scala's.
  • Case Classes,来自 Scala 的简单代数数据类型
  • 来自函数式编程世界的模式匹配
  • 尾调用优化
  • Quasiquotes,一种操作程序片段的快速方法
  • 字符串插值,很多语言的共同特性,Pyxl。
  • 跟踪和智能断言
  • PINQ to SQLAlchemy,C# 中 LINQ to SQL 的克隆
  • 来自 Scala 和 Groovy 的快速 Lambda,
  • 解析器组合器,灵感来自Scala 的.

Check out the linked page to find out more; I think I can confidently say that the use cases we demonstrate far surpass anything anyone's suggested so far on this thread =D

查看链接页面以了解更多信息;我想我可以自信地说,我们展示的用例远远超过了迄今为止任何人在此线程上提出的任何建议 =D

回答by vsedach

Here's one real-world example I came across that would be trivial with macros or real metaprogramming support, but has to be done with CPython bytecode manipulation due to absence of both in Python:

这是我遇到的一个真实示例,它对于宏或真正的元编程支持来说是微不足道的,但由于 Python 中两者都没有,因此必须使用 CPython 字节码操作来完成:

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

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

This is how the problem is solved in Common Lisp using a combination of regular macros, and read-macros to extend the syntax (it could have been done without the latter, but not the former):

这就是在 Common Lisp 中使用常规宏和读取宏的组合来解决问题的方法来扩展语法(可以在没有后者的情况下完成,但没有前者):

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

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

The same problem solved in Smalltalk using closures and metaprogramming (Smalltalk is one of the few single-dispatch OO languages that actually gets message passing right):

在 Smalltalk 中使用闭包和元编程解决了同样的问题(Smalltalk 是少数真正正确传递消息的单分派 OO 语言之一):

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

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

Here I tried to implement the Smalltalk approach in Common Lisp, which is a good illustration of how metaprogramming is poorly supported in the latter:

在这里,我尝试在 Common Lisp 中实现 Smalltalk 方法,这很好地说明了后者如何支持元编程:

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

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

回答by bigmonachus

In lisp, macros are just another way to abstract ideas.

在 lisp 中,宏只是抽象思想的另一种方式。

This is an example from an incomplete ray-tracer written in clojure:

这是一个用 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]
       ~@body)))

If you want to do something to every pixel with coordinates (i,j), say, draw a black pixel if i is even, you would write:

如果您想对坐标为 (i,j) 的每个像素执行某些操作,例如,如果 i 为偶数,则绘制一个黑色像素,您可以这样写:

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

This is not possible to do without macros because @body can mean anything inside (per-pixel i j @body)

没有宏这是不可能的,因为@body 可以表示内部的任何内容(每像素 ij @body)

Something like this would be possible in python as well. You need to use decorators. You can't do everything you can do with lisp macros, but they are very powerful

在 python 中也有可能发生这样的事情。你需要使用装饰器。你不能用 lisp 宏做你能做的一切,但它们非常强大

Check out this decorator tutorial: http://www.artima.com/weblogs/viewpost.jsp?thread=240808

查看此装饰器教程:http: //www.artima.com/weblogs/viewpost.jsp?thread=240808

回答by lfaraone

There's a mailing list posting(archive.org mirror) which explains this rather well. The post is about Perl, but it applies to Python just as well.

有一个邮件列表帖子archive.org mirror)很好地解释了这一点。这篇文章是关于 Perl 的,但它也适用于 Python。

回答by Rick Copeland

Some uses cases I have seen before include making class factoriesor stripping loggingstatements out of production code.

我之前见过的一些用例包括创建类工厂或从生产代码中剥离日志语句。

回答by Chris Jester-Young

See also this question: Pythonic macro syntax

另见这个问题:Pythonic 宏语法

回答by Chris Jester-Young

I don't think Python needs macros, because they are useful for 2 things:

我认为 Python 不需要宏,因为它们对两件事很有用:

  1. Creating a DSL or more eloquent syntax for something (Lisp LOOP macro is a nice example). In this case, Python philosophy decided against it deliberately. If there is some explicit notation you're missing, you can always ask for a PEP.

  2. Making things faster by precomputing things at compile time. Python isn't oriented to speed, so you can always use a function instead.

  1. 为某事创建 DSL 或更雄辩的语法(Lisp LOOP 宏就是一个很好的例子)。在这种情况下,Python 哲学故意反对它。如果您遗漏了一些明确的符号,您可以随时要求提供 PEP。

  2. 通过在编译时预先计算东西来使事情变得更快。Python 不以速度为导向,因此您始终可以使用函数来代替。

I am not saying macros are wrong, just that they don't fit Python philosophy. You can always do without them without much code duplication, because you have duck typing and operator overloading.

我并不是说宏是错误的,只是它们不符合 Python 哲学。你总是可以不用它们而没有太多的代码重复,因为你有鸭子类型和运算符重载。

And as a side note, I would much rather see Lisp's restarts in Python than macros.

作为旁注,我更愿意看到 Lisp 在 Python 中的重启而不是宏。

回答by grettke

Read "The Lambda Papers" so you might find out generally why one would take advtage of macros at all.

阅读“Lambda 论文”,这样您可能会大致了解为什么人们会完全利用宏。

You should start with ‘AIM-353 Lambda:The Ultimate Imperative' and follow it with ‘AIM-443 Lambda: The Ultimate GOTO'. Both may be found here:

你应该从“AIM-353 Lambda:The Ultimate Imperative”开始,然后用“AIM-443 Lambda: The Ultimate GOTO”。两者都可以在这里找到:

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

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