简体   繁体   English

当 l 是生成器时无法测试“x in l”

[英]Cannot test "x in l" when l is a generator

Question问题

I am trying to understand the difference between a list comprehension and a generator expression:我试图了解列表理解和生成器表达式之间的区别:

x = 25

if x in [i**2 for i in range(100)]:
    print('list version: {} is a square!'.format(x))
# list version: 25 is a square!

if x in (i**2 for i in range(100)):
    print('generator version: {} is a square!'.format(x))
# generator version: 25 is a square!

When called once, they both appear to do the same thing.当调用一次时,它们似乎都在做同样的事情。 So there isn't a difference?所以没有区别吗?

But then I try them in a loop:但后来我循环尝试它们:

l = [i**2 for i in range(100)]
g = (i**2 for i in range(100))

print('list version')
for x in range(20, 51):
    if x in l:
        print('{} is a square!'.format(x))
# list version
# 25 is a square!
# 36 is a square!
# 49 is a square!

print('generator version')
for x in range(20, 51):
    if x in g:
        print('{} is a square!'.format(x))
# generator version
# 

In the generator version, no square is found.在生成器版本中,没有找到正方形。 Why?为什么? What's different between a generator and a list?生成器和列表有什么不同?

Context语境

I am trying to solve the following problem: Given a number n (n > 0) I must produce the smallest square number N (N > 0) such that n + N is also a perfect square.我正在尝试解决以下问题:给定一个数字n (n > 0) ,我必须产生最小的平方数N (N > 0) ,使得n + N也是一个完美的平方。 If no response is received, return -1.如果没有收到响应,则返回 -1。

I have the following code:我有以下代码:

def solve(n):
    # l = [i**2 for i in range(10**2)]
    l = (i**2 for i in range(10*4))
    r = -1
    for i in l:
        if n + i in l:
            return i
        else:
            r = -1
    return r

It works when I use list comprehension l = [i**2 for i in range(10**2)] , but not when I use generator l = (i**2 for i in range(10*4) .它在我使用列表理解l = [i**2 for i in range(10**2)]时有效,但在我使用生成器l = (i**2 for i in range(10*4)时无效。

I verified this code in Python visualizer and it does not enter the loop if I use the generating algorithm.我在 Python 可视化工具中验证了此代码,如果我使用生成算法,它不会进入循环。

Could you please assist me?你能帮帮我吗?

Understanding generators了解生成器

A list is a data structure: the elements in a list are stored in memory and can be looked at, modified, added or deleted at will.列表是一种数据结构:列表中的元素存储在memory中,可以随意查看、修改、添加或删除。

By contrast, a generator is a lazy structure.相比之下,生成器是惰性结构。 The elements in a generator are generated and consumed when they are looked at.生成器中的元素是在查看时生成和消耗的。 They are not generated sooner, and will not be regenerated later.它们不会更早生成,以后也不会重新生成。 Let's look at an example:让我们看一个例子:

# lists
>>> l = [i**2 for i in range(5)]
>>> l
[0, 1, 4, 9, 16]
>>> l
[0, 1, 4, 9, 16]
>>> l
[0, 1, 4, 9, 16]

# generators
>>> g = (i**2 for i in range(5))
>>> g
<generator object <genexpr> at 0x7fbec28e5970>
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> list(g)
[9, 16]
>>> list(g)
[]
>>> list(g)
[]

Initially, g is ready to generate all elements 0,1,4,9,16 .最初, g已准备好生成所有元素0,1,4,9,16 But every element will only be generated once.但是每个元素只会生成一次。 Once we've seen the 0, and the 1, and the 4, we won't see them again.一旦我们看到了 0、1 和 4,我们就不会再看到它们了。 When we call list(g) after having already seen the first three elements, we get a list of only the last two elements.当我们在已经看到前三个元素之后调用list(g)时,我们会得到一个仅包含最后两个元素的列表。 And if we try to call list(g) again after that, we get an empty list, because there are no elements left to generate.如果我们在此之后再次尝试调用list(g) ,我们会得到一个空列表,因为没有剩余的元素可以生成。

In your code, you use the operator in to test whether an element is in a generator.在您的代码中,您使用运算符in来测试元素是否在生成器中。 Let's play with in :让我们in一下:

>>> g = (i**2 for i in range(5))
>>> 4 in g
True
>>> 9 in g
True
>>> 1 in g
False
>>> 16 in g
False
>>> 4 in g
False

What happened?发生了什么? First, g was ready to generate 0,1,4,9,16 .首先, g准备好生成0,1,4,9,16 Then we asked whether 4 in g ?然后我们问是否4 in g So the first three elements were generated, and 4 was found: we got the answer True and now g has only two elements left to generate.所以生成了前三个元素,找到了4 :我们得到了答案True ,现在g只剩下两个元素要生成了。 Then we ask: 9 in g ?然后我们问: 9 in g One more element is generated, 9 is found, we get the answer True and now g only has one more element left to generate.再生成一个元素,找到 9,我们得到答案True ,现在g只剩下一个要生成的元素了。 Then we ask 1 in g ?然后我们问1 in g ? Since there is no 1 left to generate, all elements remaining are generated, and 1 is not found.由于没有剩下1可以生成,所以剩下的所有元素都生成了,没有找到1 We get the answer False and now g is exhausted.我们得到了False的答案,现在g已经用尽了。 Now, any question we ask will get the answer False : there is nothing left in g .现在,我们提出的任何问题都会得到答案Falseg中什么都没有了。

Relevant documentation相关文件

I suggest reading the python tutorial, and its section on iterators and generators .我建议阅读python 教程及其关于迭代器和生成器的部分

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM