Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use yield in Python

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

I believe many inexperienced people don't know what to do about how to use yield in Python. Therefore, this article summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

How to generate Fibonacci number series

The Fibonacci number series is a very simple recursive series. Any number except the first and second numbers can be obtained by adding the first two numbers. Using a computer program to output the first N of the Fibonacci series is a very simple problem, and many beginners can easily write the following functions:

Listing 1. Simply output the top N of Fibonacci series

Example #! / usr/bin/python#-*-coding: UTF-8-*-def fab (max): n, a, b = 0,0,1 while n

< max: print b a, b = b, a + b n = n + 1fab(5) 执行以上代码,我们可以得到如下输出: 1 1 2 3 5 结果没有问题,但有经验的开发者会指出,直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。 要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List。以下是 fab 函数改写后的第二个版本: 清单 2. 输出斐波那契數列前 N 个数第二版 实例#!/usr/bin/python# -*- coding: UTF-8 -*- def fab(max): n, a, b = 0, 0, 1 L = [] while n < max: L.append(b) a, b = b, a + b n = n + 1 return L for n in fab(5): print n 可以使用如下方式打印出 fab 函数返回的 List: 1 1 2 3 5 改写后的 fab 函数通过返回 List 能满足复用性的要求,但是更有经验的开发者会指出,该函数在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,最好不要用 List 来保存中间结果,而是通过 iterable 对象来迭代。例如,在 Python2.x 中,代码: 清单 3. 通过 iterable 对象来迭代 for i in range(1000): pass 会导致生成一个 1000 个元素的 List,而代码: for i in xrange(1000): pass 则不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。因为 xrange 不返回 List,而是返回一个 iterable 对象。 利用 iterable 我们可以把 fab 函数改写为一个支持 iterable 的 class,以下是第三个版本的 Fab: 清单 4. 第三个版本 实例#!/usr/bin/python# -*- coding: UTF-8 -*- class Fab(object): def __init__(self, max): self.max = max self.n, self.a, self.b = 0, 0, 1 def __iter__(self): return self def next(self): if self.n < self.max: r = self.b self.a, self.b = self.b, self.a + self.b self.n = self.n + 1 return r raise StopIteration() for n in Fab(5): print n Fab 类通过 next() 不断返回数列的下一个数,内存占用始终为常数: 1 1 2 3 5 然而,使用 class 改写的这个版本,代码远远没有第一版的 fab 函数来得简洁。如果我们想要保持第一版 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了: 清单 5. 使用 yield 的第四版 实例#!/usr/bin/python# -*- coding: UTF-8 -*- def fab(max): n, a, b = 0, 0, 1 while n < max: yield b # 使用 yield # print b a, b = b, a + b n = n + 1 for n in fab(5): print n 第四个版本的 fab 和第一版相比,仅仅把 print b 改为了 yield b,就在保持简洁性的同时获得了 iterable 的效果。 调用第四版的 fab 和第二版的 fab 完全一致: 1 1 2 3 5 简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。 也可以手动调用 fab(5) 的 next() 方法(因为 fab(5) 是一个 generator 对象,该对象具有 next() 方法),这样我们就可以更清楚地看到 fab 的执行流程: 清单 6. 执行流程 >

> > f = fab (5) > f.next () 1 > > f.next () 1 > > f.next () 2 > f.next () 3 > > f.next () 5 > f.next () Traceback (most recent call last): File ", line 1, in StopIteration

When the function execution ends, generator automatically throws a StopIteration exception, indicating that the iteration is complete. In the for loop, there is no need to handle the StopIteration exception and the loop ends normally.

We can draw the following conclusions:

A function with yield is a generator, which, unlike an ordinary function, generates a generator that looks like a function call, but does not execute any function code until it is called next () (which is automatically called next () in the for loop). Although the execution process still follows the flow of the function, each time a yield statement is executed, it breaks and returns an iterative value, and the next execution continues from the next statement in yield. It looks as if a function has been interrupted by yield several times during normal execution, and each interrupt returns the current iterative value through yield.

The benefits of yield are obvious. Rewriting a function to a generator gains iterative ability. Compared with using an instance of the class to save state to calculate the value of the next next (), not only the code is concise, but also the execution process is extremely clear.

How to determine whether a function is a special generator function? You can use isgeneratorfunction to judge:

Listing 7. Use isgeneratorfunction to judge

> from inspect import isgeneratorfunction > isgeneratorfunction (fab) True

Note the distinction between fab and fab (5), where fab is a generator function and fab (5) is a generator returned by calling fab, similar to the difference between a class definition and an instance of a class:

Listing 8. Definition of a class and instances of a class

> import types > isinstance (fab, types.GeneratorType) False > isinstance (fab (5), types.GeneratorType) True

Fab cannot be iterated, while fab (5) is iterable:

> from collections import Iterable > isinstance (fab, Iterable) False > isinstance (fab (5), Iterable) True

Each time the fab function is called, a new generator instance is generated, and each instance does not affect each other:

> > f1 = fab (3) > f2 = fab (5) > print 'f1: 1 > print 'f2: 1 > > print 'f1: 1 > > print 'f2: 1 > > f2.next () f2: 1 > print 'f1: 2 > print'f2: 2 > > print'f2, f2.next () f2: 2 > print'f2: f2.next () f2: 3 > print F2.next () f2: the role of 5return

In a generator function, if there is no return, the default execution is to the end of the function, and if return is in the process of execution, a StopIteration is thrown directly to terminate the iteration.

Another example

Another example of yield comes from file reading. If you call the read () method directly on a file object, it results in unpredictable memory footprint. A good way is to use a fixed-length buffer to constantly read the contents of the file. With yield, we no longer need to write iterative classes to read files, and we can easily read files:

Listing 9. Another example of yield

Example def read_file (fpath): BLOCK_SIZE = 1024 with open (fpath, 'rb') as f: while True: block = f.read (BLOCK_SIZE) if block: yield block else: return after reading the above, have you mastered how to use yield in Python? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report