在python学习过程中,像这些使用if else流程控制或者说函数的定义和使用都比较好理解,但是生成器是一个相对来说很难理解的概念,使用也就相对困难,本文将详细解析python里面的生成器。

1.什么是python生成器

python生成器generator是一个通过调用yield返回一个可迭代的生成器的函数。yield将会返回一个值,当再次调用next()的时候就返回下一个值。而不是从函数的开头开始执行,这里我们举个例子。


def my_generator():
    print("first element:")
    yield 1
    print("second element:")
    yield 2
    print("second element:")
    yield 3
a = my_generator()
next(a)
next(a)
next(a)

《python生成器generator,yield》

在上述例子中,生成器实例a,第一次调用a的next()方法时,函数似乎执行到yield 1,就暂停了.然后再次调用next()时,函数从yield 1之后开始执行的,并再次暂停.第三次调用next(),从第二次暂停的地方开始执行.第四次,抛出StopIteration异常。

实际情况是,生成器在遇到yield之后暂停了,准确的说,是先返回了yield表达式的值,然后再暂停的。当再次调用生成器的next()时,从先前暂停的地方开始执行,直到遇到下一个yield。当再次使用next的时候,由于函数已经没有了,抛出异常。

要避免这种生成器的异常,使用for语句会自动结束。

2.Generator生成器与function普通函数区别

function每次都是从第一行开始运行,而generator从上一次yield开始的地方运行 。

function调用一次返回一个(一组)值,而generator可以多次返回。

function可以被无数次重复调用,而一个generator实例在yield最后一个值 或者return之后就不能继续调用了,会抛出终止迭代错误(StopIteration)

3.Generator生成器应用

生成斐波拉契数列

def Fibonacci():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a+b 
fib = Fibonacci()

上面代码是一个斐波拉契数列的生成器,每次调用都输出一个值,然后想要多少位,使用多少次next()即可。

在实际应用中,使用生成器可以极大的提高程序运行效率,降低使用内存,比如像读入基因组测序文件fastq时,如果一次读入将会直接占用相当多的内存,而使用生成器可以在普通的机器上就能够进行分析。

4.注意事项

1.Yield不能嵌套

def get_num(data):
    for i in data:
        if isinstance(i, tuple) or isinstance(i, list):
            get_num(i) # here value retuened is generator
        else:
            yield i
for i in get_num([1, 2, (3, 4), 5]):
    print(i)

上述代码将会返回1,2,5的数组,而不会返回1,2,3,4,5如果要返回1,2,3,4,5的话,不能直接调用自身,而应该使用yield from,修改后的代码:

def get_num(data):
    for i in data:
        if isinstance(i, tuple) or isinstance(i, list):
            yield from get_num(i) # here value retuened is generator
        else:
            yield i

for e in get_num([1, 2, (3, 4), 5]):
    print(e)

《python生成器generator,yield》

2. 生成器generator返回不能带返回值

def yield_with_return(num):
     if num < 0:
         return 0
     else:
         for i in range(num):
             yield i
mynum = yield_with_return(-1)

会报错

《python生成器generator,yield》

正确做法是return不能有返回值

def yield_with_return(num):
     if num < 0:
         return 
     else:
         for i in range(num):
             yield i
mynum = yield_with_return(-1)

5.总结

本文详细介绍了python3里面的生成器generator的用法及其原理,要提高变成技巧还需在实际应用中使用生成器。

1.Generator生成器是为了生成一系列的值

2.Yield就像普通函数的return,而生成器的return是用来抛出异常的

3.Yield是为了保存当前函数执行的状态

4.生成器generator与迭代器iterator的特例

5.使用next(generator)返回生成器的下一个值