6

我正在浏览 WikiVS 的一些页面,我引用了这些页面:

因为 Python 中的 lambda 仅限于表达式,不能包含语句

我想知道这个限制在哪里是一个很好的例子(或更多),最好是与 Ruby 语言相比。

感谢您的回答、评论和反馈!

4

5 回答 5

14

我不认为你真的在问 lambdas,而是在问内联函数

这确实是 Python 非常恼人的限制之一:你不能内联定义一个函数(一个真正的函数,而不仅仅是一个表达式);你必须给它一个名字。这是非常令人沮丧的,因为所有其他现代脚本语言都会这样做,并且不得不将函数移出线外通常是非常痛苦的。这也令人沮丧,因为我感觉 Python 字节码可以简单地表示这一点——只是语言语法不能。

Javascript:

responses = {
        "resp1": {
                "start": function() { ...  },
                "stop": function() { ... },
        },
        "resp2": {
                "start": function() { ...  },
                "stop": function() { ... },
        },
        ...
}
responses["resp1"]["start"]();

卢阿:

responses = {
        resp1 = {
                start = function() ...  end;
                end = function() ...  end;
        };
        ...
}
responses.resp1.start();

红宝石:

responses = {
    "resp1" => {
        "start" => lambda { },
        "stop" => lambda { },
    },
}
responses["resp1"]["start"].call

Python:

def resp1_start():
    pass
def resp1_stop():
    pass
responses = {
    "resp1": {
        "start": resp1_start,
        "stop": resp1_stop,
    },
}
responses["resp1"]["start"]()

请注意,JavaScript 和 Lua 没有 lambda:它们没有理由存在,因为内联函数以更自然和通用的方式覆盖它们。

我可能会将其评为最烦人的日常 Python 限制。

于 2010-04-16T17:20:53.113 回答
9

最常遇到的关于语句的情况可能是 Python 2.X 的print语句。

例如,

say_hi = lambda name: "Hello " + name

按预期工作。

但这不会编译:

say_hi = lambda name: print "Hello " + name

因为print在 Python 2 中不是一个合适的函数。

>>> say_hi = lambda name: "Hello " + name
>>> say_hi("Mark")
'Hello Mark'
>>> 
>>> say_hi = lambda name: print "Hello " + name
SyntaxError: invalid syntax

其余的语句print可以在 Python 在线文档中找到:

simple_stmt ::=  expression_stmt
                 | assert_stmt
                 | assignment_stmt
                 | augmented_assignment_stmt
                 | pass_stmt
                 | del_stmt
                 | print_stmt
                 | return_stmt
                 | yield_stmt
                 | raise_stmt
                 | break_stmt
                 | continue_stmt
                 | import_stmt
                 | global_stmt
                 | exec_stmt

如果你想看到它们失败,你可以在 REPL 中尝试其余的:

>> assert(True)
>>> assert_lambda = lambda: assert(True)
SyntaxError: invalid syntax
>>> pass
>>> pass_lambda = lambda: pass
SyntaxError: invalid syntax

我不确定 Python 的lambda限制和 Ruby 的proclambda. 在 Ruby 中,一切都是消息,因此您没有关键字(好吧,您确实有关键字,但没有关键字看起来像 Python 的函数print)。在我的脑海中,没有容易被误解的 Ruby 结构会在proc.

于 2010-04-16T16:06:52.580 回答
4

我有时想到的一个例子是这样的:

def convert(value):
    n = expensive_op(value)
    return (n, n + 1)

new_list = map(convert, old_list)

虽然它足够简短和甜美,但你不能将它转换为 lambda 而不必运行expensive_op()两次(顾名思义,你不想这样做),即你必须这样做

new_list = map(lambda v: (expensive_op(v), expensive_op(v) + 1), old_list)

因为 assignment ( n = ...) 是一个语句。

于 2010-04-16T16:12:43.830 回答
2

而不是f=lambda s:pass你可以做的f=lambda s:None

于 2010-07-09T01:24:12.317 回答
1

lambda只是 Python 中定义返回简单表达式的函数的一种快捷方式。这不是任何有意义的限制。如果您需要的不仅仅是一个表达式,那么只需使用一个函数:对于lambda,没有什么是您无法使用函数做的。

使用函数而不是 lambda 的唯一缺点是该函数必须在 1 个或多个单独的行上定义(因此与 lambda 相比,您可能会失去一些局部性),并且您必须为函数发明一个名称(但是如果你想不出一个,那么f通常可以工作)。

人们认为他们必须使用 lambda 的所有其他原因(例如访问嵌套变量或使用单独的默认参数生成大量 lambda)都可以与函数一起使用。

使用命名函数的最大优势当然是当它出错时,您可以获得有意义的堆栈跟踪。昨天当我得到一个涉及 lambda 的堆栈跟踪并且没有关于它是哪个 lambda 的上下文时,我被我咬了。

于 2010-04-16T16:58:56.093 回答