Python 30 天 – 第 15 天 – 生成器(什么是生成器)

作者 : 慕源网 本文共2653个字,预计阅读时间需要7分钟 发布时间: 2021-10-13 共488人阅读

本文是 30 天 Python 挑战系列的一部分。您可以在此处找到本系列之前所有帖子的链接

今天我探讨了 Python 中生成器的所有概念。在JavaScript 中也存在生成器的概念。它是在 ES6 版本的 JavaScript 中引入的,但我在实际的 JavaScript 项目中并没有太多使用它们。今天在阅读它们时,我意识到它们非常有用,并且被用于多个 Python 库和框架中。

那么什么是生成器?

生成器是一种特殊的函数,它返回一组可迭代的值,一次一个,这意味着它可以循环遍历以逐个获取值。它有时也被称为可以“暂停”的功能。理论上,生成器听起来相当复杂和令人困惑。最好使用代码示例进行解释。我们已经使用内置的 Python 生成器range来生成一系列值。

range_of_numbers = range(100) # 一个生成器    
for num in range_of_numbers:   
    print(num)  
# 由于 range 是一个生成器,所以它可以被迭代或循环   
def my_infinite_generator():  
  num = 0  
  while True:  
    yield num  
    num +=1  
  
result = my_infinite_generator()  
for i in result:  
  print(i) # Keeps on printing values infinitely!  

那么这个生成器函数到底是什么,它与普通函数有什么不同呢?

使用 return 语句,函数只能返回一个值。一旦函数到达 return 语句,它就会返回值并退出。而生成器函数可以使用特殊关键字返回任意数量的值yield。每当yield到达该语句时,函数执行就会暂停,并且控制权被传递给调用该函数的任何人。

生成器的值可以通过迭代或使用另一个next在生成器上调用的内置函数来提取。在上面的代码块中,生成器的值是使用iteration (for 循环)打印的。可以使用该next函数手动完成相同的操作。

def my_infinite_generator():  
  num = 0  
  while True:  
    yield num  
    num +=1  
  
result = my_infinite_generator()  
print(next(result)) # 0  
print(next(result)) # 1  
print(next(result)) # 2  
print(next(result)) # 3  
print(next(result)) # 4  

请注意生成器函数如何能够记住num的值并能够增加它。无论何时yield到达语句,它都会保存局部变量及其状态,然后将控制权转移给调用者。

def my_generator(max):  
  num = 0  
  while num < 3:  
    yield num  
    num +=1  
  
result = my_generator(3)  
print(next(result)) # 0  
print(next(result)) # 1  
print(next(result)) # 2  
print(next(result)) # Stop Iteration Error 

当迭代完成时(在上述情况下,一旦 num = 3),生成器函数会在进一步next调用时自动引发 StopIteration 异常。如果使用 for 循环迭代同一个生成器,一旦生成器引发 StopIteration,循环将自动停止。for 循环在内部处理并终止。

使用生成器的性能优势

生成器函数是内存高效的。在处理需要大量处理来计算结果的大量数据时,生成器确实派上用场。内存是一种有限资源,我们的系统只能在内存中保存有限数量的数据。

例如,如果我们必须创建一个函数来接受一个数字并打印斐波那契数列直到该数字,传统的方法将是这样的

def fibonacci(num):  
  sequence = []  
  a,b = 0,1  
  for item in range(num):  
    sequence.append(a)  
    temp = a  
    a = b  
    b = temp + b  
  return sequence  
  
result = fibonacci(20)  
print(result) # prints the fibonacci sequence  

在上面的函数中,整个序列作为列表存储在内存中。只有在整个序列存储在内存中后才会打印结果。当数量很少时,这通常很好。但是,如果数量很大,内存使用量会急剧增加,如果内存溢出,甚至可能会杀死进程。

使用生成器可以提高上述功能的内存效率

def fibonacci_generator(num):  
  a,b = 0,1  
  for item in range(num):  
    yield a  
    temp = a  
    a = b  
    b = temp + b  
  
for num in fibonacci_generator(20):  
  print(num)  

在这种情况下,一次只有一个值存储在内存中,因此即使提供的数字非常大,它也可以打印值。

Composition

生成器可以组合在一起,换句话说,它们可以通过管道连接在一起以组合来自不同生成器的结果。

例如,如果我们必须创建一个每个值都平方的斐波那契数列,则可以使用两个生成器函数来组合它们。

def fibonacci_generator(num):  
  a,b = 0,1  
  for item in range(num):  
    yield a  
    temp = a  
    a = b  
    b = temp + b  
  
def square(nums):  
  for num in nums:  
    yield num**2  
  
result = square(fibonacci_generator(5))  
  
for num in result:  
  print(num) # 0 1 1 4 9  

这种组合在计算大型数据集并分层对它们应用不同的操作时非常有用。

这就是关于 Python 中生成器的全部内容。今天探索生成器帮助我巩固了围绕这个概念的心智模型,我现在可能也可以想出在 JavaScript 中实现它们的方法。

明天标志着当前 Python 挑战的第三周开始,根据我计划的路线图,我将探索 Python 中的另一个重要主题 – 模块。我相信这会很有趣。


慕源网 » Python 30 天 – 第 15 天 – 生成器(什么是生成器)

常见问题FAQ

程序仅供学习研究,请勿用于非法用途,不得违反国家法律,否则后果自负,一切法律责任与本站无关。
请仔细阅读以上条款再购买,拍下即代表同意条款并遵守约定,谢谢大家支持理解!

发表评论

开通VIP 享更多特权,建议使用QQ登录