Python 发电机评估时间偏差的解决方法
从今天开始,我发现自己在“评估时间差异”项下遇到了问题,我很难解决这个问题 作为我问题的一个简短演示,我制作了无限多个生成器,跳过每一个Python 发电机评估时间偏差的解决方法,python,generator,Python,Generator,从今天开始,我发现自己在“评估时间差异”项下遇到了问题,我很难解决这个问题 作为我问题的一个简短演示,我制作了无限多个生成器,跳过每一个nth数字,其中n从[2..5]开始: from itertools import count skip_lists = [] for idx in range(2, 5): # skip every 2nd, 3rd, 4th.. number skip_lists.append(x for x in count() if (x % idx)
n
th数字,其中n
从[2..5]
开始:
from itertools import count
skip_lists = []
for idx in range(2, 5):
# skip every 2nd, 3rd, 4th.. number
skip_lists.append(x for x in count() if (x % idx) != 0)
# print first 10 numbers of every skip_list
for skip_list in skip_lists:
for _, num in zip(range(10), skip_list):
print("{}, ".format(num), end="")
print()
预期产出:
1, 3, 5, 7, 9, 11, 13, 15, 17, 19,
1, 2, 4, 5, 7, 8, 10, 11, 13, 14,
1, 2, 3, 5, 6, 7, 9, 10, 11, 13,
实际产量:
1, 2, 3, 5, 6, 7, 9, 10, 11, 13,
1, 2, 3, 5, 6, 7, 9, 10, 11, 13,
1, 2, 3, 5, 6, 7, 9, 10, 11, 13,
一旦我想起了这个伟大的特性,我就试图通过将
if
子句变量绑定到一个常量来“解决”它,该常量将是跳过列表的一部分
from itertools import count
skip_lists = []
for idx in range(2, 5):
# bind the skip distance
skip_lists.append([idx])
# same as in the first try, but use bound value instead of 'idx'
skip_lists[-1].append(x for x in count() if (x % skip_lists[-1][0]) != 0)
# print first 10 numbers of every skip_list
for skip_list in (entry[1] for entry in skip_lists):
for _, num in zip(range(10), skip_list):
print("{}, ".format(num), end="")
print()
但是,再一次:
1, 2, 3, 5, 6, 7, 9, 10, 11, 13,
1, 2, 3, 5, 6, 7, 9, 10, 11, 13,
1, 2, 3, 5, 6, 7, 9, 10, 11, 13,
除了一个实际的解决方案,我还想知道为什么我的破解没有成功。直到您开始迭代生成器(生成器被惰性地评估),才会查找idx
的值,此时idx=4
最新的迭代对象值就是模块范围中的值
通过将idx
传递给函数并在每个生成器的求值时从函数范围读取值,可以使每个附加的生成器在idx
中有状态。这利用了这样一个事实,即生成器表达式的iterable源在gen.exp的创建时进行求值,因此在循环的每次迭代中调用函数,并且idx
安全地存储在函数作用域中:
from itertools import count
skip_lists = []
def skip_count(skip):
return (x for x in count() if (x % skip) != 0)
for idx in range(2, 5):
# skip every 2nd, 3rd, 4th.. number
skip_lists.append(skip_count(idx))
gen.exp创建时生成器表达式的iterable源计算示例:
>>> (i for i in 5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
回答得很好,我的代码现在可以工作了=),但恐怕我仍然不明白为什么在跳过列表中存储idx
。追加([idx])
并访问它而不是idx
不起作用。该值不会更改为上一次迭代,print(skip_list)
最终生成第二个示例的[[2,]、[3,]、[4,]
。生成器表达式的代码对象在计算时读取名称idx
,这是在第一次循环完成之后。更像是在循环之后打印idx
。在那一点上的名称idx
引用了int 4。这太可怕了。甚至没有跳过列表。append([lambda x=idx:x])
用于创建本地范围的引用。谢谢你告诉我如何解决这个问题。这并不可怕。这就是懒惰的代价。我认为在另一种情况下,附加的lambda函数应该有不同的idx
绑定值。然后更正:如果有一种直接的方法来进行范围界定,即不包括使用函数来进行范围界定,我将更容易理解python中的惰性求值。我不明白你的第二句话。对于lambda,skip_列表[x][0]()
分别产生2、3、4
。但是当生成器调用它时,它显然仍然是4,4,4
>>> (i for i in range(2) if i in 5)
<generator object <genexpr> at 0x109a0da50>
from itertools import islice
for skip_list in skip_lists:
for num in islice(skip_list, 10):
print("{}, ".format(num), end="")
print()