Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python宏:用例?_Python_Macros_Lisp_Scheme - Fatal编程技术网

Python宏:用例?

Python宏:用例?,python,macros,lisp,scheme,Python,Macros,Lisp,Scheme,如果Python有一个类似于Lisp/Scheme(类似于)的宏工具,您将如何使用它 如果你是一名Lisp/Scheme程序员,你使用宏做什么(除了Python中有明确语法并行的东西,比如while循环)?我以前见过的一些用例包括用生产代码生成或声明。有一个()可以很好地解释这一点。这篇文章是关于Perl的,但它同样适用于Python。我认为宏的运行与Python的文化背道而驰。Lisp中的宏允许这种方法;您需要重新定义语言,使其更适合您的问题领域。相反,Pythonic代码使用Python最自

如果Python有一个类似于Lisp/Scheme(类似于)的宏工具,您将如何使用它


如果你是一名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不需要宏,因为它们有两个用途:

  • 为某些东西创建DSL或更具说服力的语法(Lisp LOOP macro是一个很好的例子)。在这种情况下,Python哲学故意反对它。如果缺少一些明确的符号,您可以随时请求PEP

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

  • 我并不是说宏是错的,只是它们不符合Python的理念。没有宏,您总是可以不用太多代码重复,因为您有duck类型和运算符重载

    另外,我更希望看到Lisp在Python中重新启动,而不是宏。

    阅读“Lambda论文”,这样您就可以大致了解为什么会使用宏

    您应该以“AIM-353 Lambda:终极命令”开头,然后以“AIM-443 Lambda:终极GOTO”结尾。两者都可以在这里找到:


    这里有一个我遇到的实际示例,它对于宏或真正的元编程支持来说是微不足道的,但由于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(),))