Python宏:用例?
如果Python有一个类似于Lisp/Scheme(类似于)的宏工具,您将如何使用它Python宏:用例?,python,macros,lisp,scheme,Python,Macros,Lisp,Scheme,如果Python有一个类似于Lisp/Scheme(类似于)的宏工具,您将如何使用它 如果你是一名Lisp/Scheme程序员,你使用宏做什么(除了Python中有明确语法并行的东西,比如while循环)?我以前见过的一些用例包括用生产代码生成或声明。有一个()可以很好地解释这一点。这篇文章是关于Perl的,但它同样适用于Python。我认为宏的运行与Python的文化背道而驰。Lisp中的宏允许这种方法;您需要重新定义语言,使其更适合您的问题领域。相反,Pythonic代码使用Python最自
如果你是一名Lisp/Scheme程序员,你使用宏做什么(除了Python中有明确语法并行的东西,比如while循环)?我以前见过的一些用例包括用生产代码生成或声明。有一个()可以很好地解释这一点。这篇文章是关于Perl的,但它同样适用于Python。我认为宏的运行与Python的文化背道而驰。Lisp中的宏允许这种方法;您需要重新定义语言,使其更适合您的问题领域。相反,Pythonic代码使用Python最自然的内置特性来解决问题,而不是用另一种语言更自然的方式来解决问题
宏本质上是非音速的 在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]
~@body)))
如果你想用坐标(i,j)对每个像素做点什么,比如说,画一个黑色像素,如果我是偶数,你会写:
(per-pixel i,j
(if (even? i)
(draw-black i,j)))
unless is_superman():
dodge_bullet()
switch x:
case FOO:
do_stuff_with_foos()
case BAR:
do_stuff_with_bars()
case BAZ:
do_stuff_with_bazs()
如果没有宏,这是不可能的,因为@body可以表示内部的任何内容(每像素i j@body)
类似的事情在python中也是可能的。你需要使用装饰器。
你不能用lisp宏做所有的事情,但是它们非常强大
查看此装饰器教程:
lisp宏的一些示例:
- 这是一个有趣且可扩展的循环工具
- /它们是在编译时生成解析器的解析器生成器
- 它允许指定包含静态和动态部分的html文档
- 这是一个javascript代码生成器
- 各种简单的代码包装器,例如错误处理程序(我有一个with gtk错误消息处理程序,它执行代码并在发生未处理的错误时显示GtkMessageDialog)、执行器(例如,给定一个代码,在不同的线程中执行;我有一个主线程内宏,在不同的线程中执行代码;库使用宏包装要同时执行的代码)
- 具有宏的GUI构建器(例如,指定小部件层次结构和小部件属性,并具有用于创建所有小部件的宏生成代码)
- 在编译期间使用外部资源的代码生成器。例如,处理C头并生成FFI代码的宏或基于数据库架构生成类定义的宏
- 声明性FFI。例如,指定外部结构、函数及其参数类型,并使用宏生成相应的lisp结构、具有类型映射和封送代码的函数
- 基于Continuations的通用Lisp web框架使用宏将代码转换为CPS(continuationpassingstyle)形式
这里有一个我遇到的实际示例,它对于宏或真正的元编程支持来说是微不足道的,但由于Python中缺少这两种支持,因此必须使用CPython字节码操作来完成: 这就是如何在Common Lisp中使用常规宏和读取宏的组合来解决问题,以扩展语法(可以在没有后者的情况下完成,但没有前者的情况下完成): 使用闭包和元编程在Smalltalk中解决了相同的问题(Smalltalk是为数不多的真正正确传递消息的单一分派OO语言之一): 在这里,我尝试在Common Lisp中实现Smalltalk方法,这很好地说明了元编程在后者中的支持情况如何: 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"
for i in range(10):
result=i*i
print result
if result==25:
print "I knew that 5*5 == 25"
其他语法:
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(5):
print "Hi everybody"
print "See you soon"
print "stop"
for i in range(10):
result=i*i
print result
if result==25:
print "I knew that 5*5 == 25"
此外,Espy有两个功能:“宏用于”和“宏如果”。例如:
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."
完整的文档和免费下载可在以下位置找到:
我在很多情况下都使用这个模块。它允许更结构化和更短的代码。有了它,我从1000行espy代码中生成了65000行清晰高效的python代码,用于一个新的国际象棋引擎项目(仍在进行中)
如果Python可以在未来的版本中包含宏,它会给人留下深刻的印象。如果您希望在运行时获得源代码,例如用于调试(比如printf调试表达式的名称,这样您就不必编写两次)
好吧,我想要代替
print >> sys.stderr, "abc"
写
err "abc"
在一些包含许多调试打印输出语句的脚本中
我能行
import sys
err = sys.stderr
然后
print >> err, "abc"
它较短,但仍然占用了太多的字符。我想使用宏在pyth中启用sql语句
switch x:
case FOO:
do_stuff_with_foos()
case BAR:
do_stuff_with_bars()
case BAZ:
do_stuff_with_bazs()
@case
class Point(x, y)
p = Point(1, 2)
print p.x # 1
print p # Point(1, 2)
if logger.level > logger.DEBUG:
logger.log('%s' % (an_expensive_call_that_gives_useful_info(),))
DEBUG('%s' % (an_expensive_call_that_gives_useful_info(),))