我可能不太了解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)
为什么?怎么做才能避免呢?
答案 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
接受一个函数和一个迭代。只要函数返回takewhile
,True
就会从迭代中产生。我使用的函数是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()
,从不。