python为什么lambda在与调用随机函数的常量比较时表现不同

时间:2017-03-22 22:56:40

标签: python lambda

我可能不太了解python的lambda。所以它让我感到困惑。例如,如果我有这个简单的lambda构造与常量,一切都很完美:

>>> f = lambda max,x=0:[ x for x in iter(lambda: x+0.5,max+1.) if x<max ]
>>> f(10)
[0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5]

但如果我用随机数生成器代替常数0.5,它就会卡住并且永远不会返回....

>>> f = lambda max,x=0:[ x for x in iter(lambda: x+random.random(),max+1.) if x<max ]
>>> f(10)

为什么?怎么做才能避免呢?

2 个答案:

答案 0 :(得分:4)

iter(lambda: x+0.5,max+1.)函数返回完全 lambda时,

max+1.会停止。该函数确实返回max+1.,因此迭代器停在那里,但是浮点舍入可能会有所不同。

iter(lambda: x+random.random(),max+1.)仅在lambda函数准确返回max+1.时停止,但这次,该函数极不可能返回该值。你的列表理解永远过滤迭代器元素。

请注意,您的两个代码段都依赖于Python 2列表解析变量范围行为,其中理解的x子句中的for与函数中的x相同理解中出现了。在Python 3中有所改变,因此你的代码片段都不适用于Python 3。

答案 1 :(得分:2)

以下是实现目标的一些方法。首先,一些代码 - 高尔夫:

def f(stop): 
    return itertools.takewhile(functools.partial(operator.gt, stop), itertools.accumulate(iter(random.random, object())))

我会让你把它解读为一种练习(探索itertools的好方法!)。还有一个很好的教训,就是为什么你不应该写出神秘的单行...

但是,我可能只会这样做:

In [5]: def increase_random(stop, start=0):
    ...:     start += random.random()
    ...:     while start < stop:
    ...:         yield start
    ...:         start += random.random()
    ...:

看看有多可读和直截了当?从现在起6个月后,我将重新阅读并确切知道我的目的。

这是在行动:

In [7]: list(increase_random(5))
Out[7]:
[0.442800767759875,
 1.4148173965715438,
 1.7683959590284435,
 2.116245564487893,
 2.832867264471769,
 3.684055219689638,
 3.986469894067608,
 4.617838198100095]

In [8]: list(increase_random(5))
Out[8]:
[0.5851100455307873,
 1.3248041125729781,
 2.275952338784795,
 2.539203591128045,
 2.7563520512088835,
 3.259124317278677,
 4.1641913798928805,
 4.77771351014472]

In [9]: list(increase_random(10))
Out[9]:
[0.4226041227598847,
 1.0816534967326379,
 1.1540685081566209,
 1.6987578052795809,
 2.118172344169681,
 2.5349681976516156,
 3.137101744986478,
 3.1436528694585766,
 3.455139268185562,
 3.7614777591407975,
 4.072603396579612,
 4.71137983138932,
 5.01309327918888,
 5.098769083492201,
 5.858553103139947,
 5.950601116127209,
 5.956983974085873,
 5.967975512928789,
 6.090114835094137,
 6.105296749316677,
 6.329459825745162,
 6.825175725633318,
 7.738665256248604,
 8.409407710225171,
 9.202163699315623,
 9.497148670699866,
 9.839990622387328,
 9.977297575005993]

好的,这是对阅读这篇文章的奖励......这样的单行程如此:

itertools.takewhile接受一个函数和一个迭代。只要函数返回takewhileTrue就会从迭代中产生。我使用的函数是functools.partial(operator.gt, stop),它是operator.gt的部分应用,op.gt(a, b)相当于a > b,因此我们需要stop更长时间比iteterable返回的值。最后,iterable是itertools.accumulate(iter(random.random, object())accumulate(仅在Python 3上)采用可迭代并继续向其添加iterables值...即累积。所以,例如:

In [10]: list(itertools.accumulate([1, 2, 3, 4]))
Out[10]: [1, 3, 6, 10]

我传递给accumulate的可迭代是iter(random.random, object()),它只调用random.random,直到值为== object()从不