在python中的匿名函数的配方?

时间:2013-03-27 11:26:17

标签: python anonymous-function

我正在寻找最好的收件人,以允许在python中内联定义函数或多行lambda。

例如,我想做以下事情:

def callfunc(func):
   func("Hello")

>>> callfunc(define('x', '''
...     print x, "World!"
... '''))
Hello World!

我在this answer中找到了define函数的示例:

def define(arglist, body):
    g = {}
    exec("def anonfunc({0}):\n{1}".format(
        arglist,
        "\n".join("    {0}".format(line) for line in body.splitlines())), g)
    return g["anonfunc"]

这是一种可能的解决方案,但并不理想。可取的功能将是:

  • 对缩进更加明智,
  • 更好地隐藏内脏(例如,在功能的范围内没有anonfunc
  • 提供对周围范围/捕获中的变量的访问
  • 更好的错误处理

还有一些我没有想过的事情。一旦完成上述大部分工作,我都有一个非常好的实现,但不幸的是我输了。我想知道是否其他人做了类似的事情。

声明:

我很清楚这在Python用户中是有争议的,并被视为黑客或unpythonic。我也知道在python-dev邮件列表上讨论多行lambda的讨论,并且故意省略了类似的功能。然而,从同样的讨论中我了解到,许多其他人也对这种功能感兴趣。

我不是在问这是不是一个好主意,而是:鉴于已经决定实施这个,(要么出于好玩和好奇心,疯狂,真实地认为这是一个好主意,或被枪口持有)如何使用python(2.7或3.x)当前使define尽可能接近def工作设施吗

示例:

有关原因的更多信息,这对于GUI中的回调非常方便:

# gtk example:
self.ntimes = 0
button.connect('clicked', define('*a', '''
    self.ntimes += 1
    label.set_text("Button has been clicked %d times" % self.ntimes)
''')

使用def定义函数的好处是您的代码更符合逻辑。这是从Twisted应用程序中获取的简化代码:

# twisted example:
def sayHello(self):
    d = self.callRemote(HelloCommand)
    def handle_response(response):
        # do something, this happens after (x)!
        pass
    d.addCallback(handle_response) # (x)

请注意它似乎无序。我经常打破这样的东西,保持代码顺序==执行顺序:

def sayHello_d(self):
    d = self.callRemote(HelloCommand)
    d.addCallback(self._sayHello_2)
    return d

def _sayHello_2(self, response):
    # handle response
    pass

这是更好的。订购但更详细。现在,使用匿名函数技巧:

d = self.callRemote(HelloCommand)
d.addCallback(define('response', '''
    print "callback"
    print "got response from", response["name"]
'''))

1 个答案:

答案 0 :(得分:2)

如果你来自javascript或ruby背景,python处理匿名函数的能力可能看起来确实有限,但这是有原因的。 Python设计者认为清晰的代码比简洁更重要。如果你不喜欢它,你可能根本不喜欢python。这没什么不对的,还有很多其他的选择 - 为什么不尝试一种对你来说味道更好的语言呢?

将代码块放入字符串并动态解释它们绝对是一种“扩展”语言的错误方法,因为你正在使用的工具 - 从语法高亮显示器到python解释器本身 - 都不能以合理的方式处理“字符串化”代码。

回答问题:你在做什么实际上是尝试构建一些比python更好的编程语言,并在运行时将其编译为python。这个想法在脚本语言世界中并不新鲜,并且可以提高效率(CoffeeScript是成功实现的一个例子),但是你的方法是错误的。在使用代码时,format()不是您正在寻找的工具。如果您正在编写编译器,请正确执行:使用解析器(例如pyparsing)来读取AST中的代码,遍历AST以生成python代码(甚至字节码),随时捕获语法错误并采取措施提供更好的运行时反馈(例如错误上下文,行号等)。最后,确保您的编译器适用于不同的python版本和实现。

或者只使用红宝石。