Python 从生成器到列表
Python from generator to list
我看过一些示例,我们可以将 generator
转换为 list
,如下所示。
第一个例子:
print [2 * n for n in range(5)]
# same as the list comprehension above
print list(2 * n for n in range(5))
第二个例子:
def double(L):
for x in L:
yield x*2
# eggs will be a generator
eggs = double([1, 2, 3, 4, 5])
# the above is equivalent to ("generator comprehension"?)
eggs = (x*2 for x in [1, 2, 3, 4, 5])
# need to do this if you need a list
eggs = list(double([1, 2, 3, 4, 5]))
print eggs
# the above is equivalent to (list comprehension)
eggs = [x*2 for x in [1, 2, 3, 4, 5]]
print eggs
我的问题是,是否可以将所有generators
都转换成list
?(我在下面的例子中失败了):
def get_primes(number):
while True:
if is_prime(number):
number = yield number
number += 1
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
generator = get_primes(5)
print list(generator)
输出:TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int'
问题出在这里:number = yield number
出于某种原因。对此的一些解释表示赞赏。
你的发电机坏了:
number = yield number
这应该只是 yield number
。将 yield
表达式的值分配给变量仅在您希望调用者将 send
值传递给生成器时才有用。当你正常地迭代一个生成器时,它的所有 yield 表达式的计算结果都是 None
。此行将 None
分配给 number
,然后分配 number += 1
TypeErrors,因为您正在尝试将整数添加到 None
.
如果您曾尝试使用 for
循环迭代此生成器,您会遇到同样的错误。
也就是说,并非所有生成器都可以转换为列表,您的代码,无论是固定的还是未固定的,都是原因的一个示例:生成器可能会永远抛出异常或产生值。 list
构造函数大致等同于
def list(arg):
l = []
for item in arg:
l.append(arg)
return l
如果生成器抛出异常,异常会传播到 list
构造函数之外并终止循环。如果生成器永远产生,循环将永远进行下去,或者至少直到您 运行 内存不足或耐心不足为止。你也可以有一个拒绝屈服的发电机:
def noyield():
while True:
pass
yield 1 # Not happening.
这里有 2 个问题:
number = yield number
会将 number
设置为 None
(因为您没有 send
任何生成器)。
第二个问题是:您的生成器永远不会终止。如果你从那个 python 生成一个列表可能 运行 进入内存溢出。
这是你可以做的:
import math
def get_primes(start, stop):
n = start
while True:
if n >= stop:
raise StopIteration
if is_prime(n):
yield n
n += 1
def is_prime(number):
# no changes here
generator = get_primes(5, 15)
print list(generator) # [5, 7, 11, 13]
除了 StopIteration
之外,任何不引发异常并终止的生成器都可以转换为列表。
改变
number += 1
到
number = number + 1 if (number is not None) else 1
这样一来,您只会在有内容发送给号码时更新号码,并避免上述异常。 但是如果您不向生成器发送值,您将覆盖数字。
但是@hiro主角描述的两个问题依然存在!
我看过一些示例,我们可以将 generator
转换为 list
,如下所示。
第一个例子:
print [2 * n for n in range(5)]
# same as the list comprehension above
print list(2 * n for n in range(5))
第二个例子:
def double(L):
for x in L:
yield x*2
# eggs will be a generator
eggs = double([1, 2, 3, 4, 5])
# the above is equivalent to ("generator comprehension"?)
eggs = (x*2 for x in [1, 2, 3, 4, 5])
# need to do this if you need a list
eggs = list(double([1, 2, 3, 4, 5]))
print eggs
# the above is equivalent to (list comprehension)
eggs = [x*2 for x in [1, 2, 3, 4, 5]]
print eggs
我的问题是,是否可以将所有generators
都转换成list
?(我在下面的例子中失败了):
def get_primes(number):
while True:
if is_prime(number):
number = yield number
number += 1
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
generator = get_primes(5)
print list(generator)
输出:TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int'
问题出在这里:number = yield number
出于某种原因。对此的一些解释表示赞赏。
你的发电机坏了:
number = yield number
这应该只是 yield number
。将 yield
表达式的值分配给变量仅在您希望调用者将 send
值传递给生成器时才有用。当你正常地迭代一个生成器时,它的所有 yield 表达式的计算结果都是 None
。此行将 None
分配给 number
,然后分配 number += 1
TypeErrors,因为您正在尝试将整数添加到 None
.
如果您曾尝试使用 for
循环迭代此生成器,您会遇到同样的错误。
也就是说,并非所有生成器都可以转换为列表,您的代码,无论是固定的还是未固定的,都是原因的一个示例:生成器可能会永远抛出异常或产生值。 list
构造函数大致等同于
def list(arg):
l = []
for item in arg:
l.append(arg)
return l
如果生成器抛出异常,异常会传播到 list
构造函数之外并终止循环。如果生成器永远产生,循环将永远进行下去,或者至少直到您 运行 内存不足或耐心不足为止。你也可以有一个拒绝屈服的发电机:
def noyield():
while True:
pass
yield 1 # Not happening.
这里有 2 个问题:
number = yield number
会将 number
设置为 None
(因为您没有 send
任何生成器)。
第二个问题是:您的生成器永远不会终止。如果你从那个 python 生成一个列表可能 运行 进入内存溢出。
这是你可以做的:
import math
def get_primes(start, stop):
n = start
while True:
if n >= stop:
raise StopIteration
if is_prime(n):
yield n
n += 1
def is_prime(number):
# no changes here
generator = get_primes(5, 15)
print list(generator) # [5, 7, 11, 13]
除了 StopIteration
之外,任何不引发异常并终止的生成器都可以转换为列表。
改变
number += 1
到
number = number + 1 if (number is not None) else 1
这样一来,您只会在有内容发送给号码时更新号码,并避免上述异常。 但是如果您不向生成器发送值,您将覆盖数字。
但是@hiro主角描述的两个问题依然存在!