【问题标题】:Cannot test "x in l" when l is a generator当 l 是生成器时无法测试“x in l”
【发布时间】:2022-01-14 05:13:52
【问题描述】:

问题

我试图理解列表理解和生成器表达式之间的区别:

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!

当调用一次时,它们似乎都在做同样的事情。所以没有区别?

然后我循环尝试它们:

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
# 

在生成器版本中,没有找到正方形。为什么?生成器和列表有什么区别?

上下文

我正在尝试解决以下问题:给定一个数字n (n > 0),我必须生成最小的平方数N (N > 0),这样n + N 也是一个完美的平方。如果没有收到响应,返回-1。

我有以下代码:

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

当我使用列表理解 l = [i**2 for i in range(10**2)] 时它有效,但当我使用生成器 l = (i**2 for i in range(10*4) 时无效。

我在 Python 可视化工具中验证了这段代码,如果我使用生成算法,它不会进入循环。

你能帮帮我吗?

【问题讨论】:

  • “它不”是什么意思?
  • 它不适合发电机
  • 您需要提供哪些详细信息?我是这个平台的新手,也许我忘了说明什么
  • 它有什么作用?你是怎么得出它没有进入循环的结论的?例如,您尝试过for i in l: print(i) 吗?你自己研究了什么来解决它? How to Ask
  • 你应该提到“不起作用”的含义:它是否产生错误的输出(哪个),它是否产生一个错误(哪个),它是否挂起,......等等。我们希望您提供调试信息。

标签: python algorithm generator


【解决方案1】:

了解生成器

列表是一种数据结构:列表中的元素存储在内存中,可以随意查看、修改、添加或删除。

相比之下,生成器是lazy 结构。生成器中的元素在查看时会生成和使用。它们不会更早生成,以后也不会重新生成。我们来看一个例子:

# 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)
[]

最初,g 已准备好生成所有元素 0,1,4,9,16。但是每个元素只会生成一次。一旦我们看到了 0、1 和 4,我们就不会再看到它们了。当我们在已经看到前三个元素之后调用list(g) 时,我们会得到一个仅包含最后两个元素的列表。如果我们在此之后再次尝试调用list(g),我们会得到一个空列表,因为没有剩余的元素可以生成。

在您的代码中,您使用运算符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

发生了什么?首先,g 已准备好生成 0,1,4,9,16。然后我们问是否4 in g?所以生成了前三个元素,并找到了4:我们得到了答案True,现在g 只剩下两个元素要生成了。然后我们问:9 in g?又生成了一个元素,找到了 9,我们得到了答案 True,现在 g 只剩下一个要生成的元素了。那我们问1 in g?由于没有剩下要生成的1,所以剩余的所有元素都生成了,没有找到1。我们得到了答案False,现在g 已经筋疲力尽了。现在,我们提出的任何问题都会得到答案False:g 中什么都没有。

相关文档

我建议阅读the python tutorial, and its section on iterators and generators。

【讨论】:

    猜你喜欢
    • 2019-07-09
    • 1970-01-01
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 2013-01-27
    • 1970-01-01
    • 2023-02-07
    相关资源
    最近更新 更多