Python学习第四十二天—函数8(生成器)

[复制链接]
15271953841 发表于 2024-3-6 07:56:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

×
本帖最后由 15271953841 于 2024-3-6 08:01 编辑

Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
有没有办法让函数在退出之后,还能保留状态呢?闭包的定义复杂;全局变量也可实现。
一、        有没有一种既简单又安全的方法呢?——生成器
用yield表达式来代替我们函数中的return的语句就可以了

def counter():
    i=0
    while i <= 5:
        yield I       (yield保留函数过程中的结果)
        i += 1

        
counter()                   (现在调用counte函数,得到的不再是返回值,而是一个生成器)
<generator object counter at 0x000002250B813C40>
for i in counter():                (如何使用这个生成器呢?把它放到for语句中,)
    print(i)

   
0
1
2
3
4
5
c=counter()                         ( 生成器看作制作机器,每调用一次,提供一个数据,并且会记住当时的状态,而列表、元组这些可迭代对象则是容器,它们里面存放的是早已准备所有数据。生成器可以看作一种特殊的迭代器,它不走回头路,支持next函数。)
c
<generator object counter at 0x000002250B813D00>
next(c)
0
next(c)
1
next(c)
2
next(c)
3
next(c)
4
next(c)
5
next(c)
Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    next(c)
StopIteration
由于生成器每调用一次获取一个结果这样的特性,导致生成器对象无法使用下标索引这种随机访问的方式了。
c=counter()
c[2]
Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    c[2]
TypeError: 'generator' object is not subscriptable
学习闭包时有一道作业题:用闭包来求斐波那契数列。斐波那契数列由0和1开始,之后的斐波那契数就由之前的两个数相加而得出:0,1,1,2,3,5,8,……。用生成器实现方式:
def fib():
    back1,back2=0,1
    while True:
        yield back1
        back1,back2=back2,back1+back2

        
f=fib()
next(f)
0

next(f)
1
next(f)
1
next(f)
2
next(f)
3
next(f)
5
next(f)
8
next(f)
13
next(f)
21
next(f)
34
next(f)
55
for I in f:
print(i)

   
89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418,……后面会无穷无尽的打印,直到死机,据说ctrl+C可以中途退出,但我没有推出成功,直接关闭Python程序.
Python用闭包函数实现斐波那契数列的方法
方法一:

seq = [0,1]
def fib(seq,n):
    if n ==1:
        seq.pop()
        return seq
    elif n == 2:
        return seq
    elif n > 2:
        for i in range(n - 2):
            seq.append(seq[-1] + seq[-2])
return seq

fib(seq,10)
   
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
fib(seq,20)
   
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418]
fib(seq,48)
   
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393]

方法二:
在编辑模式下编辑下面的程序:

#  定义斐波那契数列函数
def fib():
    back1 , back2 = 0,1
    def get_fib():
       nonlocal back1 , back2
        back1 , back2 = back2 ,back1+back2
       print(back1,end = " ")
    return get_fib
n = int(input("请输入需要几位斐波那契数列:"))
#  利用函数闭包调用斐波那契数列函数
def my_fib(n):
    f = fib()
    for i in range(n):
        f()
my_fib(n)
save保存,run module运行后,在互动模式查看:
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.

= RESTART: D:/谷兴武/创客/python学习/斐波那契数列1.py
请输入需要几位斐波那契数列:10
1 1 2 3 5 8 13 21 34 55

二、生产器表达式
(i**2 for i in range(10))       (学习元组时预告过,是一个生成器对象)
<generator object <genexpr> at 0x000002250BD798A0>
t=(i**2 for i in range(10))         (计算的是0到10之间每一个元素的平方值)
next(t)
0
next(t)
1
next(t)
4
next(t)
9
next(t)
16
next(t)
25
next(t)
36
next(t)
49
next(t)
64
next(t)
81
next(t)
Traceback (most recent call last):
  File "<pyshell#53>", line 1, in <module>
    next(t)
StopIteration
t=(i**2 for i in range(10))
for i in t:                (直接使用循环把它打印出来)
    print(i)

   
0
1
4
9
16
25
36
49
64
81
那么这种利用推导形式获得生成器的方法,我们称之为生成器表达式,生成器表达式和列表推导式最大的区别是列表推导式会一下子把所有的数据生产出来,并放到一个列表中;但是生成器表达式像一只母鸡,一次只下一个蛋,这就是实现生成器的两种方法:一个是普通函数里面的return替换成yield的表达式,另一种是直接使用生成器表达式。

QQ客服返回顶部