Python 生成器以及yield关键字

-->>>我的原文链接

一、生成器

首先提一个问题:

range(5) 和list(range(5)) 有何区别?

大家可以尝试在Python shell里键入这两个命令看看是何结果。没有意外的话,前者返回range(0,5),后者返回[0, 1, 2, 3, 4]。说明前者是一个range对象,后者是一个列表。

这还不是关键,我们分别定义一个range和相应的列表,看看前后内存占用的变化。

>>> print(psutil.Process(os.getpid()).memory_info().rss)
18161664
>>> x = list(range(10000000))
>>> print(psutil.Process(os.getpid()).memory_info().rss)
423337984 # 内存占用明显提升
>>> y = range(100000000000)
>>> print(psutil.Process(os.getpid()).memory_info().rss)
423337984 # 内存占用几乎不变

这其实就是生成器和普通列表的区别了。生成器在内存当中存储的是序列生成的逻辑,而我们一般用的列表,则是实实在在地把列表数据项放在内存里了。

应该可以体会到,当我们进行大数据的处理时,这是有显著差异的。

除此之外,我们再来看看处理时间,应该不难猜到,原理同上。

import time

t1 = time.time()
x = range(1000000)
t2 = time.time()
y = list(range(1000000))
t3 = time.time()

print(f'Time consumed for using range: {t2-t1}')
print(f'Time consumed for using list: {t3-t2}')

# Output
Time consumed for using range: 2.62e-06
Time consumed for using list: 0.031

确实,使用range几乎不占用任何时间,而用list则需要占用大量的时间。当然聪明的人一眼能看出,range只是定义了生成逻辑,真正提取数据项的时候还是需要时间的嘛,没错,但是这两个逻辑是不一样的。使用range的时候,我们每生成一项就可以对这个数据进行一些操作,但如果使用list,必须得等整个列表生成完毕才能操作。这就是为什么我们写for循环的时候都是写for i in range(x)的原因了。

二、yield关键字

yield关键字用于函数中,将该函数的返回结果变成生成器。看下面例子,给定一个数组x,需要返回一个新数组,其中每一项为原数组的平方:

# 返回list
def SquareList(x):
    result = []
    for i in x:
        result.append(i * i)
    return result

# 返回生成器
def SqaureGen(x):
    for i in x:
        yield i * i

gen = SqaureGen([1,2,3,4])
for i in gen:
    print(i)
# Output:
1
4
9
16

其中SquareGen函数通过yield关键字返回了一个生成器,效果同第一节解释的情况。

你可能感兴趣的:(Python 生成器以及yield关键字)