python生成器的惰性求值lazy evaluation例子分享

Posted on 2021-07-01 16:07  kangkang2233  阅读(179)  评论(0编辑  收藏  举报

 

希望a如果是单个元素而非可迭代对象,就重复a组成长度和b相同的生成器(其实可以用list,不过那样就没这篇文章了),每个元素都是本来的a相同,比如a=1的话,结果就是即[1,1,1,1,1,..]这样。

按直观想法写了类似如下的代码(不知道大家有没有也遇到过):

a = (a for _ in b)

测试一下,不对劲:

>>> a = 1
>>> a = (a for _ in range(5))
>>> for e in a:
...     print(e)
...
<generator object <genexpr> at 0x000001676357CB30>
<generator object <genexpr> at 0x000001676357CB30>
<generator object <genexpr> at 0x000001676357CB30>
<generator object <genexpr> at 0x000001676357CB30>
<generator object <genexpr> at 0x000001676357CB30>

!试一试把a换成1:

>>> a = (1 for _ in range(5))
>>> for e in a:
...     print(e)
...
1
1
1
1
1

嗯这就是惰性求值了,如 a = (a for _ in range(5)) 这样的表达,求值前a已经是个迭代器而不是1了,next(a)结果为a本身,输出a内的元素和输出a本身一样:

>>> for e in a:
...     print(a)
...
<generator object <genexpr> at 0x000001676357CB30>
<generator object <genexpr> at 0x000001676357CB30>
<generator object <genexpr> at 0x000001676357CB30>
<generator object <genexpr> at 0x000001676357CB30>
<generator object <genexpr> at 0x000001676357CB30>

那么手动让他勤快点呢:

>>> a = (next(a) for _ in range(5))
>>> next(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
ValueError: generator already executing

禁止套娃XD

生成器中for部份本身没有惰性求值,他们虽然都叫a,但for内的a和左边的a运行的时候已经不是一个a了。合理.jpg

>>> a = 1
>>> a = (a for _ in a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>> a = range(3)
>>> a = ((i,a) for i in a)
>>> for e in a:
...     print(e)
...
(0, <generator object <genexpr> at 0x00000167636924A0>)
(1, <generator object <genexpr> at 0x00000167636924A0>)
(2, <generator object <genexpr> at 0x00000167636924A0>)

不过如果for包含了生成器,生成器部份的变量还是会惰性求值

>>> a = range(3)
>>> a
range(0, 3)
>>> a = ((i,a) for i in a)
>>> a
<generator object <genexpr> at 0x000001676357CB30>
>>> a = ((i,a) for i in a)
>>> a
<generator object <genexpr> at 0x00000167636929E0>
>>> for e in a:
...     print(e)
...
((0, <generator object <genexpr> at 0x00000167636929E0>), <generator object <genexpr> at 0x00000167636929E0>)
((1, <generator object <genexpr> at 0x00000167636929E0>), <generator object <genexpr> at 0x00000167636929E0>)
((2, <generator object <genexpr> at 0x00000167636929E0>), <generator object <genexpr> at 0x00000167636929E0>)

迭代时,第二个表达式的for中迭代的a是第一次的生成器表达式,第二次的生成器表达式还未成型时,for就固定迭代器地址为第一次的生成器表达式,而第一个式子中(i,a)的a是惰性求值的,值为第二次的生成器表达式

 

差不多了,已经晕了,如果哪里有误或者bug,那太正常了,欢迎大家指正,也欢迎更多的讨论。其实写完感觉听浅显的,看着看着有即视感了,但是不记得在那看过类似的例子。如果有见过的大佬求帮帮!