python中嵌套的if-else lambdas返回函数对象而不是value(通过变量传递?)

时间:2015-08-08 19:17:49

标签: python lambda

我正在玩Python(2.7,通过pythonista iOS解释器)来做一些奇怪的功能性事情。具体来说,我正在尝试使用嵌套的if-else lambdas和map来实现一行fizzbuzz。但我不熟悉这种肮脏的伎俩,而且进展并不顺利。

请使用以下代码:

alist = [1, 2, 3, 15, 5]
claw = map(lambda x: 'Fizzbuzz' if x % 15 == 0 else lambda x: 'Fizz' if x % 3 == 0 else lambda x: 'Buzz' if x % 5 == 0 else x, alist)
print "claw"
print claw
print
claw2 = map(lambda x: 'scratch' if x == 1 else 2, alist)
print "claw2"
print claw2

此代码生成以下输出:

claw
[<function <lambda> at 0x3f19fb4>, <function <lambda> at 0x36ba534>, <function <lambda> at 0x3ffa3e4>, 'Fizzbuzz', <function <lambda> at 0x3ffaa74>]

claw2
['scratch', 2, 2, 2, 2]

在搜索之后,似乎爪子中的问题是列表元素没有传递给内部lambda(根据这个SO:Scope of python lambda functions and their parameters)。好吧,那么我也试着嵌套地图:

claw3 = map(lambda x: 'Fizzbuzz' if x % 15 == 0 else map(lambda x: 'Fizz' if x % 3 == 0 else map(lambda x: 'Buzz' if x % 5 == 0 else x, alist), alist), alist)
print "claw3"
print claw3

这至少产生了价值,但显然不是我想要实现的目标:

claw3
[[[1, 2, 3, 'Buzz', 'Buzz'], [1, 2, 3, 'Buzz', 'Buzz'], 'Fizz', 'Fizz', [1, 2, 3, 'Buzz', 'Buzz']], [[1, 2, 3, 'Buzz', 'Buzz'], [1, 2, 3, 'Buzz', 'Buzz'], 'Fizz', 'Fizz', [1, 2, 3, 'Buzz', 'Buzz']], [[1, 2, 3, 'Buzz', 'Buzz'], [1, 2, 3, 'Buzz', 'Buzz'], 'Fizz', 'Fizz', [1, 2, 3, 'Buzz', 'Buzz']], 'Fizzbuzz', [[1, 2, 3, 'Buzz', 'Buzz'], [1, 2, 3, 'Buzz', 'Buzz'], 'Fizz', 'Fizz', [1, 2, 3, 'Buzz', 'Buzz']]]

现在我的大脑已经用光了。显然,重复调用map会一遍又一遍地评估整个列表,但是如果没有它就无法将变量放到嵌套的lambdas中,我会卡住吗?我想可能有一些涉及改变列表的解决方案,比如每次lambda返回一个值时删除列表项,但这似乎过于复杂而且完全没有功能。我非常接近单线功能性的fizzbuzz!有没有人在这里有任何线索?

编辑:谢谢,你们。为了您的集体娱乐/奖励,一些完全实施的单行fizzbuzzes:

https://gist.github.com/paultopia/d360116128c787e22ce8

4 个答案:

答案 0 :(得分:2)

问题在于你没有召唤内在的lambda。如果条件为假,则像a if b else lambda: ...这样的表达式只返回lambda本身(即函数对象)。你可以用这个得到你的结果:

>>> claw = map(lambda x: 'Fizzbuzz' if x % 15 == 0 else (lambda x: 'Fizz' if x % 3 == 0 else (lambda x: 'Buzz' if x % 5 == 0 else x)(x))(x), alist)
>>> claw
[1, 2, 'Fizz', 'Fizzbuzz', 'Buzz']

然而,你甚至不需要做所有这些只是为了得到一个单行的fizzbuzz。您可以直接将if/else表达式直接嵌套在一个lambda中:

>>> claw = map(lambda x: 'Fizzbuzz' if x % 15 == 0 else 'Fizz' if x % 3 == 0 else 'Buzz' if x % 5 == 0 else x, alist)
>>> claw
[1, 2, 'Fizz', 'Fizzbuzz', 'Buzz']

你根本不需要任何lambdas,你只需要列表理解:

>>> claw = ['Fizzbuzz' if x % 15 == 0 else 'Fizz' if x % 3 == 0 else 'Buzz' if x % 5 == 0 else x for x in alist]
>>> claw
[1, 2, 'Fizz', 'Fizzbuzz', 'Buzz']

答案 1 :(得分:2)

如果我能提出一种稍微不同的方法,我会考虑更多的pythonic。列表推导也表达了功能操作,但在python中不那么冗长。请尝试以下方法:

claw = ['Fizzbuzz' if x % 15 == 0
        else 'Fizz' if x % 3 == 0
        else 'Buzz' if x % 5 == 0
        else x for x in alist]

在我看来,它更加清晰。

答案 2 :(得分:1)

我相信你想要的是:

claw = map(lambda x: 'fizzbuz' if x%15==0 else 'fizz' if x%3==0 else 'buzz' if x%5==0 else x, alist)

答案 3 :(得分:1)

您的问题是运营商优先级。如果你用第一个字符串替换所有lambdas之后你可以更清楚地看到这个,并添加括号来澄清:

>>> alist = [1, 2, 3, 15, 5]
>>> claw = map(lambda x: ('Fizzbuzz' if (x % 15 == 0) else "LAMBDA_FIZZ" if (x % 3 == 0) else "LAMBDA_BUZZ" if (x % 5 == 0) else x), alist)
>>> claw
[1, 2, 'LAMBDA_FIZZ', 'Fizzbuzz', 'LAMBDA_BUZZ']

BrenBarn已经发布了一个答案,显示了使用多个lambda执行此操作的方法,但是在使用map和lambda时更好的方法就是这样:

claw = map(lambda x: 'FizzBuzz' if (x % 15 == 0) else 'Fizz' if (x % 3 == 0) else 'Buzz' if (x % 5 == 0) else x, alist)

虽然我宁愿使用列表理解,即使你坚持使用单行:

claw = ['FizzBuzz' if (x % 15 == 0) else 'Fizz' if (x % 3 == 0) else 'Buzz' if (x % 5 == 0) else x for x in alist]

我实际上是这样做的:

def fizzbuzz(x):
    if x % 15 == 0:
        return 'FizzBuzz'
    elif x % 3 == 0:
        return 'Fizz'
    elif x % 5 == 0:
        return 'Buzz'
    else:
        return x

claw = [fizzbuzz(x) for x in alist]