# test_yield.pydef square_number(length): s = [] for i in range(length): s.append(i 2) return sdef square_number_yield(length): for i in range(length): yield i 2if __name__ == '__main__': length = 10 sn1 = square_number(length) sn2 = square_number_yield(length) for i in range(length): print (sn1[i], '\t', end='') print (next(sn2))
在main函数中我们比拟了两种方法实行的结果,打印在同一行上面,用end=''指令可以替代行末的换行符号,详细实行的结果如下所示:
[dechin@dechin-manjaro yield]$ python3 test_yield.py 0 01 14 49 916 1625 2536 3649 4964 6481 81
可以看到两种方法打印出来的结果是一样的。大概有些场景下便是须要持久化的存储函数中返回的结果,这一点用yield也是可以实现的,可以参考如下示例:
# test_yield.pydef square_number(length): s = [] for i in range(length): s.append(i 2) return sdef square_number_yield(length): for i in range(length): yield i 2if __name__ == '__main__': length = 10 sn1 = square_number(length) sn2 = square_number_yield(length) sn3 = list(square_number_yield(length)) for i in range(length): print (sn1[i], '\t', end='') print (next(sn2), '\t', end='') print (sn3[i])
这里利用的方法是直接将yield天生的工具转化成list格式,或者用sn3 = [i for i in square_number_yield(length)]这种写法也是可以的,在性能上该当差异不大。上述代码的实行结果如下:

[dechin@dechin-manjaro yield]$ python3 test_yield.py 0 0 01 1 14 4 49 9 916 16 1625 25 2536 36 3649 49 4964 64 6481 81 81
进阶测试
在前面的章节中我们提到,利用yield可以节省程序的内存占用,这里我们来测试一个100000大小的随机数组的平方和打算。如果利用正常的逻辑,那么写出来的程序便是如下所示(关于python内存占用的追踪方法,可以参考这一篇博客):
# square_sum.pyimport tracemallocimport timeimport numpy as nptracemalloc.start()start_time = time.time()ss_list = np.random.randn(100000)s = 0for ss in ss_list: s += ss 2end_time = time.time()print ('Time cost is: {}s'.format(end_time - start_time))snapshot = tracemalloc.take_snapshot()top_stats = snapshot.statistics('lineno')for stat in top_stats[:5]: print (stat)
这个程序一方面通过time来测试实行的韶光,另一方面利用tracemalloc追踪程序的内存变革。这里是先用np.random.randn()直接产生了100000个随机数的数组用于打算,那么自然在打算的过程中须要存储这些天生的随机数,就会占用这么多的内存空间。如果利用yield的方法,每次只产生一个用于打算的随机数,并且按照上一个章节中的用法,这个迭代天生的随机数也是可以转化为一个完全的list的:
# yield_square_sum.pyimport tracemallocimport timeimport numpy as nptracemalloc.start()start_time = time.time()def ss_list(length): for i in range(length): yield np.random.random()s = 0ss = ss_list(100000)for i in range(100000): s += next(ss) 2end_time = time.time()print ('Time cost is: {}s'.format(end_time - start_time))snapshot = tracemalloc.take_snapshot()top_stats = snapshot.statistics('lineno')for stat in top_stats[:5]: print (stat)
这两个示例的实行结果如下,可以放在一起进行比拟:
[dechin@dechin-manjaro yield]$ python3 square_sum.py Time cost is: 0.24723434448242188ssquare_sum.py:9: size=781 KiB, count=2, average=391 KiBsquare_sum.py:12: size=24 B, count=1, average=24 Bsquare_sum.py:11: size=24 B, count=1, average=24 B[dechin@dechin-manjaro yield]$ python3 yield_square_sum.py Time cost is: 0.23023390769958496syield_square_sum.py:9: size=136 B, count=1, average=136 Byield_square_sum.py:14: size=112 B, count=1, average=112 Byield_square_sum.py:11: size=79 B, count=2, average=40 Byield_square_sum.py:10: size=76 B, count=2, average=38 Byield_square_sum.py:15: size=28 B, count=1, average=28 B
经由比较我们创造,两种方法的打算韶光是险些差不多的,但是在内存占用上yield有着明显的上风。当然,大概这个例子并不是非常的恰当,但是本文紧张还是先容yield的利用方法及其运用处景。
无限长迭代器在参考链接1中提到了一种用法是无限长的迭代器,比如按顺序返回所有的素数,那么此时我们如果用return来返回所有的元素并存储到一个列表里面,便是一个非常不经济的办法,以是可以利用yield来迭代天生,参考链接1中的源代码如下所示:
def get_primes(number): while True: if is_prime(number): yield number number += 1
那么类似的,这里我们用while True可以展示一个大略的案例——返回所有的偶数:
# yield_iter.pydef yield_range2(i): while True: yield i i += 2iter = yield_range2(0)for i in range(10): print (next(iter))
由于这里我们限定了长度是10,以是终极会返回10个偶数:
[dechin@dechin-manjaro yield]$ python3 yield_iter.py 024681012141618
总结概要
本文先容了python的迭代器yield,实在关于yield,我们可以大略的将其理解为单个元素的return。这样不仅就初步理解了yield的利用语法,也能够大概理解到yield的上风,也便是在打算过程中每次只占用一个元素的内存,而不须要一贯存储大量的元素在内存中。
版权声明本文首发链接为:https://www.cnblogs.com/dechinphy/p/yield.html作者ID:DechinPhy更多原著文章请参考:https://www.cnblogs.com/dechinphy/
打赏专用链接:https://www.cnblogs.com/dechinphy/gallery/image/379634.html
参考链接https://www.cnblogs.com/coder2012/p/4990834.html