代码之家  ›  专栏  ›  技术社区  ›  Rick Copeland

Python宏:用例?

  •  21
  • Rick Copeland  · 技术社区  · 17 年前

    MetaPython )你会如何使用它?

    16 回复  |  直到 13 年前
        1
  •  12
  •   dmitry_vk    17 年前

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

    @case
    class Point(x, y)
    
    p = Point(1, 2)
    print p.x   # 1
    print p     # Point(1, 2)
    

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

    • 案例类,简单 Algebraic Data Types Scala
    • 函数式编程世界中的模式匹配
    • 准引号,一种操纵程序片段的快速方法
    • 字符串插值,许多语言中的常见功能,以及Pyxl。
    • 追踪和智能断言
    • PINQ to SQLAlchemy,C语言LINQ to SQL的克隆#
    • Scala和Groovy的Quick Lambdas,
    • 解析器组合器,灵感来自 Scala's .

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

        2
  •  15
  •   RossFabricant    17 年前

    我认为宏与Python的文化背道而驰。Lisp中的宏允许 big ball of mud

    宏本质上是非Python的。

        3
  •  13
  •   Li Haoyi    13 年前

    lisp宏的一些示例:

    • ITERATE 这是一个有趣且可扩展的循环工具
    • CL-YACC / FUCC 它们是在编译时生成解析器的解析器生成器
    • CL-WHO 它允许指定具有静态和动态部分的html文档
    • Parenscript 这是一个javascript代码生成器
    • 各种简单的代码包装器,例如错误处理程序(我有一个带gtk的错误消息处理程序,它执行代码,如果发生未处理的错误,则显示GtkMessageDialog)、执行器(例如,给定一个代码,在不同的线程中执行它;我有一个中主线程宏,在不同线程中执行代码; PCall 库使用宏来包装要并发执行的代码)
    • 带有宏的GUI构建器(例如,指定小部件的层次结构和属性,并使用宏生成代码来创建所有小部件)
    • 声明性FFI。例如,指定外部结构、函数、它们的参数类型,并使用宏来生成相应的lisp结构、具有类型映射和封送处理代码的函数
    • Common Lisp的基于延续的web框架使用宏将代码转换为CPS(延续传递样式)形式。
        4
  •  6
  •   vsedach    16 年前

    有一个 mailing list posting ( archive.org mirror )这很好地解释了这一点。这篇文章是关于Perl的,但它同样适用于Python。

        5
  •  4
  •   bigmonachus    17 年前

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

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

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

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

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

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

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

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

        6
  •  4
  •   lfaraone    16 年前

    在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)的每个像素做点什么,比如,如果i是偶数,画一个黑色像素,你可以写:

    (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

        7
  •  3
  •   Rick Copeland    17 年前

    class factories stripping logging 生产代码中的语句。

        8
  •  2
  •   Community Mohan Dere    9 年前

    我认为Python不需要宏,因为它们有两个用途:

    1. 通过在编译时预计算来加快速度。Python不是面向速度的,所以你总是可以使用函数来代替。

    顺便说一句,我宁愿看到Lisp在Python中重启,也不愿看到宏。

        9
  •  2
  •   J S    17 年前

    我会用它来包装 yield 使我能够构建更强大的发电机管道。

        10
  •  1
  •   grettke    17 年前

    目前,将功能添加到Python语言中的唯一方法是通过PEP(Python增强提案)。这可能很慢,并且在您想向语言添加仅对您的用例有用的功能的情况下对您没有帮助。

    例如, there's a PEP to add a do-while loop do-while

    PEP to add labelled break and continue 但这被拒绝了。如果带标签的break语句能让我的代码更清晰,我可以用宏来实现它们。

    除了政治公众人物,我还想 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}" (可能最好作为阅读器宏来实现)
    • 模式匹配

        11
  •  1
  •   elp    15 年前

    为了我自己的使用,我创建了一个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有两个功能:“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."
    

    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

    如果Python能在未来的版本中包含宏,它会变得更加令人印象深刻。

        12
  •  1
  •   pi.    13 年前

    我想使用宏在python代码中启用sql语句。 - 从表1中选择*

        13
  •  1
  •   Wilfred Hughes AntuanSoft    13 年前

    阅读“Lambda论文”,这样你就可以大致了解为什么人们会支持宏。

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

        14
  •  0
  •   Community Mohan Dere    9 年前

    可能是如果你想在运行时获得源代码,比如用于调试(比如printf调试一个表达式的值及其名称,这样你就不必写两次)。

    The only way I could think of to do it in python is to pass a string to eval.

        15
  •  0
  •   Evgeni Sergeev    14 年前

    好吧,我想代替

    print >> sys.stderr, "abc"
    

    err "abc"
    

    import sys
    err = sys.stderr
    

    然后

    print >> err, "abc"
    

    它更短,但仍然需要太多的字符。

        16
  •  0
  •   alex    13 年前

    来自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(),))
    
        17
  •  0
  •   Mr Fooz    12 年前