Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 发电机评估时间偏差的解决方法_Python_Generator - Fatal编程技术网

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()