4

我正在寻找允许在 python 中内联定义函数或多行 lambda 的最佳配方。

例如,我想做以下事情:

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

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

我在这个答案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 用户中是有争议的,被认为是 hack 或 unpythonic。我也知道 python-dev 邮件列表上关于多行 lambda 的讨论,并且故意省略了类似的功能。然而,从同样的讨论中,我了解到许多其他人也对这种功能感兴趣。

我不是在问这是否是一个好主意,而是:鉴于一个人已经决定实施这个,(出于乐趣和好奇,疯狂,真的认为这是一个好主意,或者被枪指着)如何使匿名define工作尽可能接近def使用 python(2.7 或 3.x)当前的设施?

例子:

关于为什么,这对于 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"]
'''))
4

1 回答 1

1

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

将大块代码放入字符串并即时解释它们绝对是“扩展”语言的错误方法,因为您正在使用的任何工具 - 从语法荧光笔到 python 解释器本身 - 都无法处理以合理的方式“字符串化”代码。

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

或者只是使用红宝石。

于 2013-03-27T11:57:11.267 回答