Python与Ruby的限制:lambda函数

6 投票
5 回答
2296 浏览
提问于 2025-04-15 21:41

我在看WikiVS上的一些页面,里面提到:

因为Python中的lambda(匿名函数)只能用来写表达式,不能包含语句。

我想知道这个限制的一个好例子(或者多个例子),最好能和Ruby语言做个对比。

谢谢大家的回答、评论和反馈!

5 个回答

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)

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

9

我们最常遇到的关于语句的情况,可能就是Python 2.X中的print语句了。

比如,

say_hi = lambda name: "Hello " + name

这个是可以正常工作的。

但是这个是无法编译的:

say_hi = lambda name: print "Hello " + name

因为在Python 2中,print并不是一个真正的函数。

>>> 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中出错。

14

我觉得你其实不是在问关于lambda的事,而是在问内联函数

这真的是Python一个让人很烦恼的限制:你不能在代码中直接定义一个函数(真正的函数,而不仅仅是一个表达式);你必须给它起个名字。这让人很沮丧,因为其他现代脚本语言都可以这样做,而不得不把函数移到外面去写常常让人很痛苦。而且我觉得Python的字节码其实可以很简单地表示这个功能——只是语言的语法不支持而已。

JavaScript:

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

Lua:

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

Ruby:

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日常使用中最让人烦恼的限制。

撰写回答