Python 简明教程
Python - Generators
Python Generators
Python 中的生成器是创建迭代器的便捷方式。它们允许我们对值序列进行迭代,这意味着值是动态生成的,而不是存储在内存中,这对于大型数据集或无限序列尤其有用。
Generators in Python are a convenient way to create iterators. They allow us to iterate through a sequence of values which means, values are generated on the fly and not stored in memory, which is especially useful for large datasets or infinite sequences.
Python 中的生成器是一种返回迭代器对象的特殊函数类型。它看上去类似于普通 Python 函数,其定义也以 def 关键字开头。但是,生成器在结尾处使用 yield 关键字,而不是使用 return 语句。
The generator in Python is a special type of function that returns an iterator object. It appears similar to a normal Python function in that its definition also starts with def keyword. However, instead of return statement at the end, generator uses the yield keyword.
Creating Generators
在 python 中主要有两种创建生成器的方法 -
There are two primary ways to create generators in python −
-
Using Generator Functions
-
Using Generator Expressions
Using Generator Functions
生成器函数使用 'yield' 语句一次性返回所有值。每次调用生成器的 next() 方法时,生成器会从上次 yield 语句之后的点继续执行。下面是创建生成器函数的示例。
The generator function uses 'yield' statement for returning the values all at a time. Each time the generator’s next() method is called the generator resumes where it left off i.e. from right after the last yield statement. Here’s the example of creating the generator function.
def count_up_to(max_value):
current = 1
while current <= max_value:
yield current
current += 1
# Using the generator
counter = count_up_to(5)
for number in counter:
print(number)
1
2
3
4
5
Using Generator Expressions
生成器表达式提供了创建生成器的简洁方法。它们使用类似于生成器表达式的语法,但使用括号即 “{}” 代替方括号即 “[]”
Generator expressions provide a compact way to create generators. They use a syntax similar to list comprehensions but used parentheses i.e. "{}" instead of square brackets i.e. "[]"
gen_expr = (x * x for x in range(1, 6))
for value in gen_expr:
print(value)
1
4
9
16
25
Exception Handling in Generators
我们可以使用带有异常处理的 'while' 循环创建生成器并对其进行遍历,以应对 'StopIteration' 异常。以下代码中的函数是一个生成器,可连续产生 1 到 5 的整数。
We can create a generator and iterate it using a 'while' loop with exception handling for 'StopIteration' exception. The function in the below code is a generator that successively yield integers from 1 to 5.
调用此函数时,它会返回一个迭代器。每次调用 next() 方法都会将控制权转移回生成器并获取下一个整数。
When this function is called, it returns an iterator. Every call to next() method transfers the control back to the generator and fetches next integer.
def generator(num):
for x in range(1, num+1):
yield x
return
it = generator(5)
while True:
try:
print (next(it))
except StopIteration:
break
Normal function vs Generator function
Python 中的普通函数和生成器函数具有不同的用途,并表现出不同的行为。了解它们之间的差异对于有效地在我们的代码中利用它们至关重要。
Normal functions and generator functions in Python serve different purposes and exhibit distinct behaviors. Understanding their differences is essential for leveraging them effectively in our code.
普通函数在被调用时计算并返回一个值或一组值,无论是在列表还是元组中。一旦返回,函数将执行完毕,所有局部变量都会被丢弃,而生成器函数会通过在每次 yield 之间暂停并恢复其状态来一次生成一个值。它使用 yield 语句,而不是 return 语句。
A normal function computes and returns a single value or a set of values whether in a list or tuple, when called. Once it returns, the function’s execution is complete and all local variables are discarded where as a generator function yields values one at a time by suspending and resuming its state between each yield. It uses the yield statement instead of return.
Example
在本例中,我们创建一个普通函数并构建一个 Fibonacci 数列表,然后使用循环遍历该列表 -
In this example we are creating a normal function and build a list of Fibonacci numbers and then iterate the list using a loop −
def fibonacci(n):
fibo = []
a, b = 0, 1
while True:
c=a+b
if c>=n:
break
fibo.append(c)
a, b = b, c
return fibo
f = fibonacci(10)
for i in f:
print (i)
Example
在上面的示例中,我们使用普通函数创建了一个 Fibonacci 数列。当我们要将所有 Fibonacci 数列数字收集到一个列表中时,再使用循环遍历该列表。假设我们希望 Fibonacci 数列达到一个大数。
In the above example we created a fibonacci series using the normal function and When we want to collect all Fibonacci series numbers in a list and then the list is traversed using a loop. Imagine that we want Fibonacci series going upto a large number.
在这样的情况下,必须将所有数字收集到一个列表中,这需要占用大量的内存。这就是生成器发挥作用的地方,因为它在列表中生成一个数字并将其提供供使用。以下代码是基于生成器的 Fibonacci 数列解决方案 -
In such cases, all the numbers must be collected in a list requiring huge memory. This is where generator is useful as it generates a single number in the list and gives it for consumption. Following code is the generator-based solution for list of Fibonacci numbers −
def fibonacci(n):
a, b = 0, 1
while True:
c=a+b
if c>=n:
break
yield c
a, b = b, c
return
f = fibonacci(10)
while True:
try:
print (next(f))
except StopIteration:
break
输出
Output
1
2
3
5
8
Asynchronous Generator
异步生成器是一个返回异步迭代器的协程。协程是由 async 关键字定义的 Python 函数,它可以调度并等待其他协程和任务。
An asynchronous generator is a co-routine that returns an asynchronous iterator. A co-routine is a Python function defined with async keyword, and it can schedule and await other co-routines and tasks.
与普通生成器一样,异步生成器在每次调用 anext() 函数时(而不是 next() 函数)在迭代器中生成增量项。
Just like a normal generator, the asynchronous generator yields incremental item in the iterator for every call to anext() function, instead of next() function.
Syntax
以下是异步生成器的语法 -
The following is the syntax of the Asynchronous Generator −
async def generator():
. . .
. . .
yield obj
it = generator()
anext(it)
. . .
Example
以下代码演示了一个协程生成器,该生成器在 async for 循环的每次迭代中生成递增的整数。
Following code demonstrates a coroutine generator that yields incrementing integers on every iteration of an async for loop.
import asyncio
async def async_generator(x):
for i in range(1, x+1):
await asyncio.sleep(1)
yield i
async def main():
async for item in async_generator(5):
print(item)
asyncio.run(main())
Example
现在,让我们编写一个 Fibonacci 数的异步生成器。为了在协程内部模拟一些异步任务,程序会在生成下一个数字之前调用 sleep() 方法,持续 1 秒钟。因此,在延迟一秒钟后,我们将在屏幕上看到数字被打印出来。
Let us now write an asynchronous generator for Fibonacci numbers. To simulate some asynchronous task inside the co-routine, the program calls sleep() method for a duration of 1 second before yielding the next number. As a result, we will get the numbers printed on the screen after a delay of one second.
import asyncio
async def fibonacci(n):
a, b = 0, 1
while True:
c=a+b
if c>=n:
break
await asyncio.sleep(1)
yield c
a, b = b, c
return
async def main():
f = fibonacci(10)
async for num in f:
print (num)
asyncio.run(main())