简体   繁体   English

Python从生成器到列表

[英]Python from generator to list

I've seen some examples where we can transfer generator into list as below. 我看过一些示例,其中我们可以将generator转移到list ,如下所示。

First example: 第一个例子:

print [2 * n for n in range(5)]
# same as the list comprehension above
print list(2 * n for n in range(5))    

Second example: 第二个例子:

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

My question is, can all generators be transferred into list ?(I failed at below example): 我的问题是,可以将所有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)

Output: TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int' 输出: TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int'

The problem is here: number = yield number for some reason. 问题在这里:由于某种原因, number = yield number Some explanation on this are appreciated. 感谢对此的一些解释。

Your generator is broken: 您的生成器已损坏:

number = yield number

This should just be yield number . 这应该只是yield number Assigning the value of a yield expression to a variable is only useful when you expect the caller to send values into the generator. 仅当期望调用者sendsend到生成器时,才将yield表达式的值分配给变量才有用。 When you just iterate over a generator normally, all its yield expressions evaluate to None . 当您正常迭代生成器时,其所有yield表达式的计算结果均为None This line assigns None to number , and then number += 1 TypeErrors because you're trying to add an integer to None . 这行代码将None分配给number ,然后将number += 1 TypeErrors分配给您,因为您试图将一个整数添加到None

If you had tried to iterate over this generator with a for loop, you would have gotten the same error. 如果您尝试使用for循环遍历此生成器,则将获得相同的错误。


That said, not all generators can be converted to a list, and your code, either fixed or unfixed, is an example of why: a generator might throw an exception or yield values forever. 就是说,并非所有生成器都可以转换为列表,并且您的代码(固定的或未固定的)都是原因的一个示例:生成器可能会抛出异常或永远产生值。 The list constructor is roughly equivalent to list构造器大致相当于

def list(arg):
    l = []
    for item in arg:
        l.append(arg)
    return l

If the generator throws an exception, the exception propagates out of the list constructor and terminates the loop. 如果生成器抛出异常,则该异常将从list构造函数中传播出去并终止循环。 If the generator yields forever, the loop goes forever, or at least until you run out of memory or patience. 如果生成器永久屈服,则循环将永久运行,或者至少直到您用尽内存或耐心为止。 You could also have a generator that refuses to yield: 您还可以使用拒绝生成的生成器:

def noyield():
    while True:
        pass
    yield 1  # Not happening.

there are 2 issues here: 这里有2个问题:

number = yield number

will set number to None (as you do not send anything to the generator). number设置为“ None (因为您不send生成器send任何内容)。

the second issue is: your generator never terminates. 第二个问题是:您的生成器永远不会终止。 if you generate a list from that python probably run into a memory overflow. 如果您从该python生成列表,则可能会遇到内存溢出。

this is what you could do: 这是您可以做的:

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]

any generator that does not raise an exception other than StopIteration and terminates can be converted to a list. 任何不引发StopIteration以外的异常并终止的生成器都可以转换为列表。

Change 更改

number += 1

to

number = number + 1 if (number is not None) else 1

In that way you would only update number if something sent to it and avoid exception mentioned above. 这样,您只会在发送了一些东西后才更新数字,并避免上述异常。 But you would override number if you won't sent value to generator. 但是,如果您不将值发送给生成器,则将覆盖数字。

But two issues described by @hiro protagonist still exist! 但是@hiro主角描述的两个问题仍然存在!

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

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