Python生成器基础 — 63、如何实现无为则无心的生成器用法?

2026-05-22 16:311阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2428个文字,预计阅读时间需要10分钟。

目录

1.为什么要生成器

2.创建生成器

1. 简单创建生成器 2. 生成器(1)的使用

3.使用 yield 关键字

1. yield 关键字说明 2. send() 方法说明

4.使用 yield 实现斐波那契数列

5.总结

目录
  • 1、为什么要有生成器
  • 2、创建生成器
    • (1)简单创建生成器
    • (2)生成器的使用
  • 3、yield关键词
    • (1)yield关键词说明
    • (2)send()方法说明
  • 4、使用yield实现斐波那契数列
  • 5、总结

1、为什么要有生成器

Python在数据科学领域可以说是很火,我想有一部分的功劳就是它的生成器了吧。

我们知道我们可以用列表储存数据,可是当我们的数据特别大的时候,列表中的数据都是放在内存中,受到内存限制,列表容量肯定是有限的,而且还会降低计算机的性能。

如果仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。但如果列表中元素是按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的列表数据,从而节省大量的空间。

换句话说,我又想要得到庞大的数据,又想让它占用空间少,这时生成器就派上用场了,它可以说是一个不怎么占计算机资源的一种方法。

2、创建生成器 (1)简单创建生成器

将一个列表推导式(也叫列表生成式) [] 改为 ()即可创建一个生成器。

# 1.用推导式定义一个列表 # 关于推导式请看以前的文章有讲解。 my_list = [x * x for x in range(10)] # 打印列表 print(my_list) # 查看my_list类型,是一个列表 print(type(my_list)) """ 输出结果: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] <class 'list'> """ # 2.创建一个生成器 my_gen = (x * x for x in range(10)) # 打印生成器,是一个生成器对象 print(my_gen) # 查看my_gen对象类型,是生成器类型 print(type(my_gen)) """ 输出结果: <generator object <genexpr> at 0x0000000002575148> <class 'generator'> """ (2)生成器的使用

# 创建生成器 my_gen = (x * x for x in range(10)) # 1。方式一:遍历生成器,使用next方法 print(my_gen.__next__()) # 0 print(my_gen.__next__()) # 1 print(my_gen.__next__()) # 4 print(my_gen.__next__()) # 9 # 或者 print(next(my_gen)) # 16 print(next(my_gen)) # 没有数据了则会抛出异常StopIteration # 2.方式二:遍历生成器的内容 for i in my_gen: print(1) # 3.方式三:遍历生成器的内容 while True: try: # 调用next函数,获取下一个字符 result = next(my_gen) print(result) except StopIteration: # 释放对it的引用,即废弃迭代器对象 del my_gen # 不推出循环会成为私循环 break

提示:

  • 在上边练习中,可以看到和迭代器的用法差不多,在这里说明一下生成器本身就是一个迭代器。如果有对迭代器不清楚的可以查看前面说明迭代器的文章。
  • 上面方式一不断调用next()方法回去元素,实在是太变态了,正确的方法是使用for循环。
  • generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

总结:

  • []推导出来的是迭代器(Iterables)。
  • ()推导出来的是生成器(Generators)。
3、yield关键词 (1)yield关键词说明

如果我们想定义一个自己的生成器函数怎么办?

Python有yield关键词。其作用和return的功能差不多,就是返回一个值给调用者,只不过有yield的函数返回值后,函数依然保持调用yield时的状态,当下次调用的时候,在原先的基础上继续执行代码,直到遇到下一个yield或者满足结束条件结束函数为止。

啥意思?啥意思?啥意思?

  • 你先把yield关键字直观的看做return关键字,它首先是return的功能,就是在函数或方法中返回某个值,返回之后程序就不再往下运行了。
  • yield相当于返回一个值给调用者,停止执行函数中的语句,并且记住这个返回的位置。下次迭代时(或者执行next方法的时候),代码从yield记录位置的下一条语句开始执行。
  • 带有yield的函数不再是一个普通函数,而是一个生成器generator
  • 调用一个生成器函数,返回的是一个迭代器对象。

示例:

# 定义一个生成器函数 def testYield(): yield 1 yield 2 yield 3 # 获得一个生成器对象 ty = testYield() """ 调用过程: next(ty)相当于ty.__next__() 掉调用一次next(ty)时 就会执行testYield()内的方法。 当执行的第一行, yield 1时, 返回当前yield的值1给调用者,停止向下执行,并记录函数中当前的执行位置。 也就是每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值。 程序执行结束 当下次再调用next(ty)的时候, 还是会执行testYield()内的方法, 只不过是从yield 1下面一句开始执行。 以此类推。 """ print(next(ty)) # 1 print(next(ty)) # 2 print(next(ty)) # 3 print(next(ty)) # StopIteration

注意:每次调用 testYield()函数都会生成一个新的 generator 实例,各实例互不影响。

(2)send()方法说明

send()方法和next()方法一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果。

def testYield(): yield 1 y = yield 2 if (y == 'hello'): yield 9 yield 3 ty = testYield() print(ty.__next__()) # 1 print(next(ty)) # 2 """ 第三次执行,send方法会把"hello"传递进去 就是y = "hello" 换句话说,就是send可以强行修改上一个yield表达式值 程序会从第二个yield的下一行开始执行 执行到下一个yield停止,并记录位置,返回结果。 """ print(ty.send("hello")) # 9 print(next(ty)) # 3 print(next(ty)) # StopIteration

注意:第一次执行要么next(ty)要么ty.send(None),不能使用ty.send('xxxxx'),否则会报错的。

4、使用yield实现斐波那契数列

""" 数学中有个著名的斐波那契数列(Fibonacci), 数列中第⼀个数0,第⼆个数1,其后的每⼀个数都可由前两个数相加得到: 如下: 0, 1, 1,2, 3, 5,8, 13, 21,34, ... 现在我们想要通过for...in...循环来遍历迭代斐波那契数列中的前n个数。 那么这个斐波那契数列我们就可以⽤生成来实现, 每次迭代都通过数学计算来⽣成下⼀个数。 """ from collections.abc import Iterable, Iterator class FibGenerator(object): """ fib数列生成器 """ # 初始化方法 def __init__(self): # 斐波拉契数列中的前两个数 self.num1 = 0 self.num2 = 1 # 用来记录迭代次数(计数器) self.i = 0 def gen(self, count): # 用来保存迭代的总次数 self.count = count # 判断是否迭代结束,如果没有到达迭代次数,则返回数据 # self.count 需要迭代的次数 # self.i已迭代次数 while self.i < self.count: yield self.num2 # 计算num1, num2的值,方便下次迭代返回 # 这里运用的是序列的封包与解包,不会的可以看我以前的文章(元组) self.num1, self.num2 = self.num2, self.num1 + self.num2 # 执行一次next方法,计数器+1 self.i = self.i + 1 # 创建一个对象 fibGen = FibGenerator() # 调用生成器函数得到一个生成器 fg = fibGen.gen(15) # fibIter对象是一个迭代器 print(isinstance(fg, Iterable)) # True print(isinstance(fg, Iterator)) # True # next方法方式获取数据 # print(next(fg)) # 1 # print(next(fg)) # 1 # print(next(fg)) # 2 # print(next(fg)) # 3 # print(next(fg)) # 5 # print(next(fg)) # 8 # 遍历生成器,可执行 for li in fg: print(li) 5、总结

  • 生成器generator就是迭代器iterator的一种,以更优雅的方式实现的iterator,而且完全可以像使用iterator一样使用generator
  • 当然除了定义,定义一个iterator,你需要分别实现__iter__()方法方法和__next__()方法。但generator只需要一个yield关键字就可以。
  • Python生成器主要目的就是为了让你的代码更省资源,更高效!

参考:

  • blog.csdn.net/weixin_37720172/article/details/78482291
  • www.cnblogs.com/liangmingshen/p/9706181.html
  • blog.csdn.net/xiangxianghehe/article/details/77281186
标签:

本文共计2428个文字,预计阅读时间需要10分钟。

目录

1.为什么要生成器

2.创建生成器

1. 简单创建生成器 2. 生成器(1)的使用

3.使用 yield 关键字

1. yield 关键字说明 2. send() 方法说明

4.使用 yield 实现斐波那契数列

5.总结

目录
  • 1、为什么要有生成器
  • 2、创建生成器
    • (1)简单创建生成器
    • (2)生成器的使用
  • 3、yield关键词
    • (1)yield关键词说明
    • (2)send()方法说明
  • 4、使用yield实现斐波那契数列
  • 5、总结

1、为什么要有生成器

Python在数据科学领域可以说是很火,我想有一部分的功劳就是它的生成器了吧。

我们知道我们可以用列表储存数据,可是当我们的数据特别大的时候,列表中的数据都是放在内存中,受到内存限制,列表容量肯定是有限的,而且还会降低计算机的性能。

如果仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。但如果列表中元素是按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的列表数据,从而节省大量的空间。

换句话说,我又想要得到庞大的数据,又想让它占用空间少,这时生成器就派上用场了,它可以说是一个不怎么占计算机资源的一种方法。

2、创建生成器 (1)简单创建生成器

将一个列表推导式(也叫列表生成式) [] 改为 ()即可创建一个生成器。

# 1.用推导式定义一个列表 # 关于推导式请看以前的文章有讲解。 my_list = [x * x for x in range(10)] # 打印列表 print(my_list) # 查看my_list类型,是一个列表 print(type(my_list)) """ 输出结果: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] <class 'list'> """ # 2.创建一个生成器 my_gen = (x * x for x in range(10)) # 打印生成器,是一个生成器对象 print(my_gen) # 查看my_gen对象类型,是生成器类型 print(type(my_gen)) """ 输出结果: <generator object <genexpr> at 0x0000000002575148> <class 'generator'> """ (2)生成器的使用

# 创建生成器 my_gen = (x * x for x in range(10)) # 1。方式一:遍历生成器,使用next方法 print(my_gen.__next__()) # 0 print(my_gen.__next__()) # 1 print(my_gen.__next__()) # 4 print(my_gen.__next__()) # 9 # 或者 print(next(my_gen)) # 16 print(next(my_gen)) # 没有数据了则会抛出异常StopIteration # 2.方式二:遍历生成器的内容 for i in my_gen: print(1) # 3.方式三:遍历生成器的内容 while True: try: # 调用next函数,获取下一个字符 result = next(my_gen) print(result) except StopIteration: # 释放对it的引用,即废弃迭代器对象 del my_gen # 不推出循环会成为私循环 break

提示:

  • 在上边练习中,可以看到和迭代器的用法差不多,在这里说明一下生成器本身就是一个迭代器。如果有对迭代器不清楚的可以查看前面说明迭代器的文章。
  • 上面方式一不断调用next()方法回去元素,实在是太变态了,正确的方法是使用for循环。
  • generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

总结:

  • []推导出来的是迭代器(Iterables)。
  • ()推导出来的是生成器(Generators)。
3、yield关键词 (1)yield关键词说明

如果我们想定义一个自己的生成器函数怎么办?

Python有yield关键词。其作用和return的功能差不多,就是返回一个值给调用者,只不过有yield的函数返回值后,函数依然保持调用yield时的状态,当下次调用的时候,在原先的基础上继续执行代码,直到遇到下一个yield或者满足结束条件结束函数为止。

啥意思?啥意思?啥意思?

  • 你先把yield关键字直观的看做return关键字,它首先是return的功能,就是在函数或方法中返回某个值,返回之后程序就不再往下运行了。
  • yield相当于返回一个值给调用者,停止执行函数中的语句,并且记住这个返回的位置。下次迭代时(或者执行next方法的时候),代码从yield记录位置的下一条语句开始执行。
  • 带有yield的函数不再是一个普通函数,而是一个生成器generator
  • 调用一个生成器函数,返回的是一个迭代器对象。

示例:

# 定义一个生成器函数 def testYield(): yield 1 yield 2 yield 3 # 获得一个生成器对象 ty = testYield() """ 调用过程: next(ty)相当于ty.__next__() 掉调用一次next(ty)时 就会执行testYield()内的方法。 当执行的第一行, yield 1时, 返回当前yield的值1给调用者,停止向下执行,并记录函数中当前的执行位置。 也就是每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值。 程序执行结束 当下次再调用next(ty)的时候, 还是会执行testYield()内的方法, 只不过是从yield 1下面一句开始执行。 以此类推。 """ print(next(ty)) # 1 print(next(ty)) # 2 print(next(ty)) # 3 print(next(ty)) # StopIteration

注意:每次调用 testYield()函数都会生成一个新的 generator 实例,各实例互不影响。

(2)send()方法说明

send()方法和next()方法一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果。

def testYield(): yield 1 y = yield 2 if (y == 'hello'): yield 9 yield 3 ty = testYield() print(ty.__next__()) # 1 print(next(ty)) # 2 """ 第三次执行,send方法会把"hello"传递进去 就是y = "hello" 换句话说,就是send可以强行修改上一个yield表达式值 程序会从第二个yield的下一行开始执行 执行到下一个yield停止,并记录位置,返回结果。 """ print(ty.send("hello")) # 9 print(next(ty)) # 3 print(next(ty)) # StopIteration

注意:第一次执行要么next(ty)要么ty.send(None),不能使用ty.send('xxxxx'),否则会报错的。

4、使用yield实现斐波那契数列

""" 数学中有个著名的斐波那契数列(Fibonacci), 数列中第⼀个数0,第⼆个数1,其后的每⼀个数都可由前两个数相加得到: 如下: 0, 1, 1,2, 3, 5,8, 13, 21,34, ... 现在我们想要通过for...in...循环来遍历迭代斐波那契数列中的前n个数。 那么这个斐波那契数列我们就可以⽤生成来实现, 每次迭代都通过数学计算来⽣成下⼀个数。 """ from collections.abc import Iterable, Iterator class FibGenerator(object): """ fib数列生成器 """ # 初始化方法 def __init__(self): # 斐波拉契数列中的前两个数 self.num1 = 0 self.num2 = 1 # 用来记录迭代次数(计数器) self.i = 0 def gen(self, count): # 用来保存迭代的总次数 self.count = count # 判断是否迭代结束,如果没有到达迭代次数,则返回数据 # self.count 需要迭代的次数 # self.i已迭代次数 while self.i < self.count: yield self.num2 # 计算num1, num2的值,方便下次迭代返回 # 这里运用的是序列的封包与解包,不会的可以看我以前的文章(元组) self.num1, self.num2 = self.num2, self.num1 + self.num2 # 执行一次next方法,计数器+1 self.i = self.i + 1 # 创建一个对象 fibGen = FibGenerator() # 调用生成器函数得到一个生成器 fg = fibGen.gen(15) # fibIter对象是一个迭代器 print(isinstance(fg, Iterable)) # True print(isinstance(fg, Iterator)) # True # next方法方式获取数据 # print(next(fg)) # 1 # print(next(fg)) # 1 # print(next(fg)) # 2 # print(next(fg)) # 3 # print(next(fg)) # 5 # print(next(fg)) # 8 # 遍历生成器,可执行 for li in fg: print(li) 5、总结

  • 生成器generator就是迭代器iterator的一种,以更优雅的方式实现的iterator,而且完全可以像使用iterator一样使用generator
  • 当然除了定义,定义一个iterator,你需要分别实现__iter__()方法方法和__next__()方法。但generator只需要一个yield关键字就可以。
  • Python生成器主要目的就是为了让你的代码更省资源,更高效!

参考:

  • blog.csdn.net/weixin_37720172/article/details/78482291
  • www.cnblogs.com/liangmingshen/p/9706181.html
  • blog.csdn.net/xiangxianghehe/article/details/77281186
标签: