Detailed explanation of yield and Generators generators
The generator and yield keyword may be one of the most powerful and difficult to understand concepts in Python (perhaps none), but it does not prevent yield from becoming the most powerful keyword in Python, for beginners It is indeed very difficult to understand. Let’s read an article written by a foreign expert about yield to help you quickly understand yield. The article is a bit long, so please be patient and read it to the end. There are some examples along the way, so you won’t feel bored.
Generator
A generator is a function composed of one or more yield expressions. Each generator is an iterator (but an iterator is not necessarily a generator).
If a function contains the yield keyword, the function will become a generator.
The generator does not return all results at once, but returns the corresponding results each time it encounters the yield keyword, and retains the current running status of the function, waiting for the next call.
Since the generator is also an iterator, it should support the next method to get the next value. (You can also use the .__next__() attribute, which is .next() in python2)
Coroutines and subroutines
We call an ordinary Python function When executing, execution generally starts from the first line of code of the function and ends with the return statement, exception or function end (can be regarded as implicitly returning None). Once the function returns control to the caller, it's all over. All work done in the function and data saved in local variables will be lost. When this function is called again, everything will be created from scratch.
This is a pretty standard process for functions discussed in computer programming. Such a function can only return a single value, but sometimes it is helpful to create a function that produces a sequence. To do this, such a function needs to be able to "save its own work".
I said that the reason for being able to "produce a sequence" is that our function does not return in the usual sense. The implicit meaning of return is that the function is returning control of the executed code to the place where the function was called. The implicit meaning of "yield" is that the transfer of control is temporary and voluntary, and our function will take back control in the future.
In Python, a "function" with this ability is called a generator, and it is very useful. Generators (and thus the yield statement) were originally introduced to make it easier for programmers to write code that produces sequences of values. Previously, to implement something like a random number generator, you would implement a class or module that generated data while keeping track of the state between each call. With the introduction of generators, this becomes very easy.
In order to better understand the problem solved by the generator, let us look at an example. As we work through this example, always keep in mind the problem we need to solve: generating a sequence of values.
Note: Outside of Python, the simplest generators are what are called coroutines. In this article, I will use this term. Remember, in Python’s concept, the coroutines mentioned here are generators. The formal term for Python is generator; coroutine is just for discussion and has no formal definition at the language level.
Example: Interesting Prime Numbers
Suppose your boss asks you to write a function. The input parameter is a list of ints and returns an iterable result containing the prime number 1.
Remember, iterator (Iterable) is just the ability of an object to return specific members each time.
You must think "this is very simple", and then quickly write the following code:
def get_primes(input_list): result_list = list() for element in input_list: if is_prime(element): result_list.append() return result_list # 或者更好一些的... def get_primes(input_list): return (element for element in input_list if is_prime(element)) # 下面是 is_prime 的一种实现... 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
The above implementation of is_prime fully meets the needs, so we tell the boss that it is done. She reported back that our function worked fine and was exactly what she wanted.
Handling infinite sequences
Oh, is that really true? A few days later, the boss came over and told us that she had encountered some small problems: she planned to use our get_primes function for a large list containing numbers. In fact, this list is so large that just creating it would use up all the system's memory. To this end, she hopes to bring a start parameter when calling the get_primes function and return all prime numbers greater than this parameter (perhaps she wants to solve Project Euler problem 10).
Let's take a look at this new requirement. Obviously it is impossible to simply modify get_primes. Naturally, it is impossible to return a list containing all the prime numbers from start to infinity (although there are many useful applications for manipulating infinite sequences). It seems that the possibility of using ordinary functions to deal with this problem is relatively slim.
Before we give up, let’s identify the core obstacle, what prevents us from writing functions that meet the boss’s new needs. Through thinking, we came to the conclusion that the function has only one chance to return the result, so it must return all the results at once. It seems pointless to draw such a conclusion; "Isn't that how functions work?" That's what we usually think. However, you can’t succeed if you don’t learn, and you don’t know if you don’t ask. “What if they are not so?”
想象一下,如果get_primes可以只是简单返回下一个值,而不是一次返回全部的值,我们能做什么?我们就不再需要创建列表。没有列表,就没有内存的问题。由于老板告诉我们的是,她只需要遍历结果,她不会知道我们实现上的区别。
不幸的是,这样做看上去似乎不太可能。即使是我们有神奇的函数,可以让我们从n遍历到无限大,我们也会在返回第一个值之后卡住:
def get_primes(start): for element in magical_infinite_range(start): if is_prime(element): return element
假设这样去调用get_primes:
def solve_number_10(): # She *is* working on Project Euler #10, I knew it! total = 2 for next_prime in get_primes(3): if next_prime < 2000000: total += next_prime else: print(total) return
显然,在get_primes中,一上来就会碰到输入等于3的,并且在函数的第4行返回。与直接返回不同,我们需要的是在退出时可以为下一次请求准备一个值。
不过函数做不到这一点。当函数返回时,意味着全部完成。我们保证函数可以再次被调用,但是我们没法保证说,“呃,这次从上次退出时的第4行开始执行,而不是常规的从第一行开始”。函数只有一个单一的入口:函数的第1行代码。
走进生成器
这类问题极其常见以至于Python专门加入了一个结构来解决它:生成器。一个生成器会“生成”值。创建一个生成器几乎和生成器函数的原理一样简单。
一个生成器函数的定义很像一个普通的函数,除了当它要生成一个值的时候,使用yield关键字而不是return。如果一个def的主体包含yield,这个函数会自动变成一个生成器(即使它包含一个return)。除了以上内容,创建一个生成器没有什么多余步骤了。
生成器函数返回生成器的迭代器。这可能是你最后一次见到“生成器的迭代器”这个术语了, 因为它们通常就被称作“生成器”。要注意的是生成器就是一类特殊的迭代器。作为一个迭代器,生成器必须要定义一些方法(method),其中一个就是__next__()【注意: 在python2中是: next() 方法】。如同迭代器一样,我们可以使用next()函数来获取下一个值。
为了从生成器获取下一个值,我们使用next()函数,就像对付迭代器一样。
(next()会操心如何调用生成器的__next__()方法)。既然生成器是一个迭代器,它可以被用在for循环中。
每当生成器被调用的时候,它会返回一个值给调用者。在生成器内部使用yield来完成这个动作(例如yield 7)。为了记住yield到底干了什么,最简单的方法是把它当作专门给生成器函数用的特殊的return(加上点小魔法)。**
yield就是专门给生成器用的return(加上点小魔法)。
下面是一个简单的生成器函数:
>>> def simple_generator_function(): >>> yield 1 >>> yield 2 >>> yield 3
这里有两个简单的方法来使用它:
>>> for value in simple_generator_function(): >>> print(value) 1 2 3 >>> our_generator = simple_generator_function() >>> next(our_generator) 1 >>> next(our_generator) 2 >>> next(our_generator) 3
魔法?
那么神奇的部分在哪里?我很高兴你问了这个问题!当一个生成器函数调用yield,生成器函数的“状态”会被冻结,所有的变量的值会被保留下来,下一行要执行的代码的位置也会被记录,直到再次调用next()。一旦next()再次被调用,生成器函数会从它上次离开的地方开始。如果永远不调用next(),yield保存的状态就被无视了。
我们来重写get_primes()函数,这次我们把它写作一个生成器。注意我们不再需要magical_infinite_range函数了。使用一个简单的while循环,我们创造了自己的无穷串列。
def get_primes(number): while True: if is_prime(number): yield number number += 1
如果生成器函数调用了return,或者执行到函数的末尾,会出现一个StopIteration异常。 这会通知next()的调用者这个生成器没有下一个值了(这就是普通迭代器的行为)。这也是这个while循环在我们的get_primes()函数出现的原因。如果没有这个while,当我们第二次调用next()的时候,生成器函数会执行到函数末尾,触发StopIteration异常。一旦生成器的值用完了,再调用next()就会出现错误,所以你只能将每个生成器的使用一次。下面的代码是错误的:
>>> our_generator = simple_generator_function() >>> for value in our_generator: >>> print(value) >>> # 我们的生成器没有下一个值了... >>> print(next(our_generator)) Traceback (most recent call last): File "<ipython-input-13-7e48a609051a>", line 1, in <module> next(our_generator) StopIteration >>> # 然而,我们总可以再创建一个生成器 >>> # 只需再次调用生成器函数即可 >>> new_generator = simple_generator_function() >>> print(next(new_generator)) # 工作正常 1
因此,这个while循环是用来确保生成器函数永远也不会执行到函数末尾的。只要调用next()这个生成器就会生成一个值。这是一个处理无穷序列的常见方法(这类生成器也是很常见的)。
执行流程
让我们回到调用get_primes的地方:solve_number_10。
def solve_number_10(): # She *is* working on Project Euler #10, I knew it! total = 2 for next_prime in get_primes(3): if next_prime < 2000000: total += next_prime else: print(total) return
我们来看一下solve_number_10的for循环中对get_primes的调用,观察一下前几个元素是如何创建的有助于我们的理解。当for循环从get_primes请求第一个值时,我们进入get_primes,这时与进入普通函数没有区别。
进入第三行的while循环
停在if条件判断(3是素数)
通过yield将3和执行控制权返回给solve_number_10
接下来,回到insolve_number_10:
for循环得到返回值3
for循环将其赋给next_prime
total加上next_prime
for循环从get_primes请求下一个值
这次,进入get_primes时并没有从开头执行,我们从第5行继续执行,也就是上次离开的地方。
def get_primes(number): while True: if is_prime(number): yield number number += 1 # <<<<<<<<<<
最关键的是,number还保持我们上次调用yield时的值(例如3)。记住,yield会将值传给next()的调用方,同时还会保存生成器函数的“状态”。接下来,number加到4,回到while循环的开始处,然后继续增加直到得到下一个素数(5)。我们再一次把number的值通过yield返回给solve_number_10的for循环。这个周期会一直执行,直到for循环结束(得到的素数大于2,000,000)。
总结
关键点:
generator是用来产生一系列值的
yield则像是generator函数的返回结果
yield唯一所做的另一件事就是保存一个generator函数的状态
generator就是一个特殊类型的迭代器(iterator)
和迭代器相似,我们可以通过使用next()来从generator中获取下一个值
通过隐式地调用next()来忽略一些值
The above is the detailed content of Detailed explanation of yield and Generators generators. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











It's no secret that Internet Explorer has fallen out of favor for a long time, but with the arrival of Windows 11, reality sets in. Rather than sometimes replacing IE in the future, Edge is now the default browser in Microsoft's latest operating system. For now, you can still enable Internet Explorer in Windows 11. However, IE11 (the latest version) already has an official retirement date, which is June 15, 2022, and the clock is ticking. With this in mind, you may have noticed that Internet Explorer sometimes opens Edge, and you may not like it. So why is this happening? exist

More and more users are starting to upgrade the win11 system. Since each user has different usage habits, many users are still using the ie11 browser. So what should I do if the win11 system cannot use the ie browser? Does windows11 still support ie11? Let’s take a look at the solution. Solution to the problem that win11 cannot use the ie11 browser 1. First, right-click the start menu and select "Command Prompt (Administrator)" to open it. 2. After opening, directly enter "Netshwinsockreset" and press Enter to confirm. 3. After confirmation, enter "netshadvfirewallreset&rdqu

June 15, 2022 is the day when Microsoft ends support for Internet Explorer 11 (IE11) and closes its legacy browser chapter. The company has been reminding users of this end-of-life date for some time and calling on them to plan a move to Microsoft Edge. Microsoft bundles IE11 with Windows 8.1 as the modern default web browser for Windows. Although it never reached the (current) heights of Chrome, it was the second most used desktop browser in 2014, behind IE8. Of course, with 20

Recently, many win10 users have found that their IE browser always automatically jumps to the edge browser when using computer browsers. So how to turn off the automatic jump to edge when opening IE in win10? Let this site carefully introduce to users how to automatically jump to edge and close when opening IE in win10. 1. We log in to the edge browser, click... in the upper right corner, and look for the drop-down settings option. 2. After we enter the settings, click Default Browser in the left column. 3. Finally, in the compatibility, we check the box to not allow the website to be reloaded in IE mode and restart the IE browser.

How to enable IE acceleration function? IE is too slow to open web pages, we can enable hardware acceleration mode in it. Many friends reported that when using IE browser, the speed of opening web pages is extremely slow, which also has a certain impact on our browsing of the web. I just want to ask the editor if there is any solution. In this case, you can turn on the hardware acceleration mode of the IE browser. The editor has compiled the method of turning on the acceleration function of IE. If you are interested, take a look below! To enable the acceleration function in IE, open the IE secure browser, click the gear-shaped "Settings" icon in the upper right corner, and select "Internet Options" to enter, as shown in the figure. 2. Click "Advanced" in the tab navigation at the head of the Internet Options window, as shown in the figure. 3.

Solutions to IE shortcuts that cannot be deleted: 1. Permission issues; 2. Shortcut damage; 3. Software conflicts; 4. Registry issues; 5. Malicious software; 6. System issues; 7. Reinstall IE; 8. Use third-party tools; 9. Check the target path of the shortcut; 10. Consider other factors; 11. Consult professionals. Detailed introduction: 1. Permission issue, right-click the shortcut, select "Properties", in the "Security" tab, make sure you have sufficient permissions to delete the shortcut. If not, you can try running as an administrator, etc.

Improvements in Generators introduced in PHP 8.1 Generators are a powerful feature introduced in PHP 5.5, which provides a more efficient way to implement iterators. In the PHP8.1 version, Generators have undergone some important improvements, bringing more convenience and flexibility to developers. In this article, we explore these improvements and illustrate their use with code examples. 1. Return key name and key value before PHP8.1

How to uninstall ie9 from win7? Computers can handle things at work and can also be used for watching TV shows. Just like watching TV dramas, we usually use browsers to watch them. Because there are more and more browsers and their functions are perfect, fewer and fewer people are using ie9 browser now. So how to uninstall the browser in win7? Take a look at win7 How to uninstall IE9 browser from the system. How to uninstall ie9 browser from win7. 1. First, double-click to open MyPC and choose to uninstall or replace the program; 2. Then find "ViewInstallUpdate" and click on it. You can find "windows internet explorer9" inside, then right-click to delete. The above is the editor with wi
