python done()函数_python之函数

生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()和__next__()方法了,

只需要一个yiled关键字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值。

deffunc():

print('====>first')

yield 1

print('====>second')

yield 2

print('====>third')

yield 3

print('====>end')

g=func()

print(g)

next(g)

next(g)

next(g)

输出结果

====>first

====>second

====>third

生成器

凡是函数体内存在yied关键,调用函数体不会执行函数体代码,会得到一个返回值,该返回值就是生成器对象

需要提示的是,生成器是一个特殊的迭代器

next的功能就是为了触发函数体的执行

yied可以让函数暂停在本次循环的位置,当再有next调用触发时,就会继续本次调用的位置继续往下执行,如此循环往复。

实例:生成器对象

def func():

print('first')

yield 1#1是自己定义的yied返回值

g=func()

print(g)

输出结果:

实例:生成器对象调用

def func():

print('first')

yield 1#1是自己定义的yied返回值

print('second')

yield 2

print('third')

yield 3

g=func() #这里是一行代码都没有运行,如果想要触发生成器,就需要调用next的方法,g呢是一个函数,

# 也将会触发g函数体内的代码执行,

res1=next(g)#会触发函数的执行,直到碰到一个yied停下来,并且将yied后的值当作本次next的结果返回

# 迭代器调用next会返回一个值,可以将值赋值给一个变量res,res只是第一次迭代返回的值

# 过程:

#1.next防止调用

# 2.g函数体内代码执行,遇到第一个yied停止,并返回结果

res2=next(g)#第二次# 迭代,返回res2

自定义一个跟内置的range函数一样的生成器

def my_range(start,stop,step):

while start < stop:

yield start

start +=step

取值方式1,使用迭代器,next触发函数运行,一个个的取出,要多少取多少,不会浪费内存空间,

再大的数字也不会担心内存溢出,但是for循环取值的话,是一次性取出范围内所有的值,如果超过容器最大的范围

会造成内存溢出

g=my_range(1,10,1)

res1=next(g)

print(res1)

res2=next(g)

print(res2)

res3=next(g)

print(res3)

res4=next(g)

print(res4)

取值方式2,使用for循环

for i in my_range(1,100000000,1):

print(i)

列表,每个元素都存在列表里

g1=[x*x for x in range(10)]

print(g1)

生成器,是一个可以产生出列表元素的算法工具,在使用时,才能产生需要的列表元素。

使用方式:

1.直接使用next()进行调用,因为生成器本身就是一个迭代器,拥有__iter__和__next__内置方法

2.可以使用for循环把生成器内的元素遍历出来,for循环使用的就是__iter__和__next__同样的机制

g2 = (x*x for x in range(10))

print(g2)

输出对比

[p1, 1, 4, 9, 16, 25, 36, 49, 64, 81]

at 0x010EE2D0>

案例1

斐波那契数列:

def fib1(max):

n,a,b=p1,p1,1

while n < max:

print(b)

a,b=b,a+b

n = n + 1

return 'done'#函数的返回值,给出函数执行的最后的结果,可以不写,但是最好带上,以免产生不必要的麻烦

fib1(10)#调用函数,执行函数体内的代码

print(fib1.__name__)#函数名字

print(fib1)#函数的内存地址

改写成生成器的方式:

def fib2(max):

n,a,b=p1,p1,1

while n

yield b

a,b=b,a+b

n = n + 1

return 'done'

f=fib2(10)#接收fib的生成器的返回值,yied的返回值定义的是b,下次next操作时是接着本次循环往后接续取值。

#第一次取值

res1=next(f)

print(res1)

#第二次取值

res2=next(f)

print(res2)

for i in fib2(6):

print(i)

案例2

def odd():

print('step 1')

yield 1 #第一次取值时,遇到yied中断,返回值为1

print('step 2')

yield(3) #第二次取值时,继续第一次中断的地方继续往下执行,

# 遇到第二个yied时中断,完成了第二次的取值,返回值3,依次进行

print('step 3')

yield(5)

o=odd()

next(o) #第一次

next(o) #第二次

next(o) #第三次

next(o)#第四次取值时因为超出了范围就报错

yied表达式形式的应用

x=yield #yied 的表达式形式

.send()#给yied传值

实例

针对yied表达式的使用,

第一步:

现使用next将函数停在yied的位置,

或者使用‘,send(None)’传一个none得值给yied,如果第一次没有传空值,就会有如下报错

def func(name):

print("%s往前跳"%name)

while True:

num=yield

print("%s往前跳了%s步"%(name,num))

f=func('joke')

输出结果

f.send(2)

f.send(2)

TypeError: can't send non-None value to a just-started generator

第二步:使用‘.send’给yied传值

第三步:使用next就可以使停在yied的位置的函数进行往下运行,while循环再次停在yied的位置

然后再‘.send’给yied传值,往复循环,就会源源不断的有值进去。

注:‘,send’本身就有next的功能,当传完值后,无需使用next,即可继续往下走

def func(name):

print("%s往前跳"%name)

while True:

num=yield

print("%s往前跳了%s步"%(name,num))

f=func('joke')

next(f)

f.send() #第一次传值,必须传空值none

f.send(2)

f.send(4)

总结:

1.yied只能在函数内使用

2.yied提供了一种自定义迭代器的解决方案

3.yied可以保存函数的暂停状态

4.yied与return

相同之处都可以返回值,值得类型和个数都没有限制

不同之处,yied可以返回多次值,return只能返回一次值

生成器表达式

l=[1,2,3,4]#列表生成式

l=(1,2,3,4)#生成器表达式,把[]换成()即可

实例

注:生成器对象在没有进行next调用时是没有进行yied执行的,即不使用不触发;不next不执行

生成器内部不存值,值是内部在每次调用时制造出来。

g=(i**2 for i in range(1,5) if i>3)

print(next(g))#停在第一次满足i>3后获得的i值处,i=4

print(next(g))#第二次进行yied操作,满足条件,停在i=5的地方

print(next(g))#第三次进行next操作的时候,已超过了范围内,就会报错,停止执行

注:为了不导致内存溢出,使用生成器

实例:

统计文件内的字符数

方式1

with open('今日内容','rt',encoding='utf-8') as f:

data=f.read()

print(len(data))

问题:所有文本的内容全部读取到内存,如果文件过大,将会导致内存不够使用,进而导致内存溢出

方式2

with open('今日内容','rt',encoding='utf-8') as f:

res=0

for line in f:

res +=len(line)

print(res)

问题:是没导致内存溢出,因为是一行一行的进行读取的,但是使用了for自己定义的循环,繁琐了很多

方式:3

with open('今日内容','rt',encoding='utf-8') as f:

print(sum(len(line) for line in f))

生成器表达式:(len(line) for line in f) #生成器对象

再使用sum内置函数求和sum()

面试关于生成器实例:

def add(n,i):

return n+i

def test():

for i in range(4):

yield i

g=test()

for n in [1,10]: #n=10

g=(add(n,i) for i in g)

分析:

第一次循环:

n=1,没有触发生成器对象的函数体代码,整个的函数的代码,将原封不动的传给g

g=(add(n,i) for i in test())

test中i=p1,1,2,3

n+i=10,11,12,13

g=(10,11,12,13)

第二次循环:

n=10时 next,触发了函数体里的代码

g=(add(n, i) for i in (add(n,i) for i in test()))

(add(n,i) for i in test())=(10,11,12,13)

n+i=20,21,22,23

g=(20,21,22,23)

print(n)

res=list(g)

迭代器1=(add(n,i) for i in test())

for i in 迭代器1: #i=next(迭代器1) i=11

add(n, i) #add(10,11)

A. res=[10,11,12,13]

B. res=[11,12,13,14]

C. res=[20,21,22,23]

D. res=[21,22,23,24]

答案:c

生成器在Python中是一个非常强大的编程结构,可以用更少地中间变量写流式代码,此外,相比其它容器对象它更能节省内存和CPU,当然它可以用更少的代码来实现相似的功能。

import time

def genrator_fun1():

a = 1

print('现在定义了a变量')

yield a

b = 2

print('现在又定义了b变量')

yield b

g1 = genrator_fun1()

print('g1 : ',g1) #打印g1可以发现g1就是一个生成器

print('-'*20) #我是华丽的分割线

print(next(g1))

time.sleep(1) #sleep一秒看清执行过程

print(next(g1))

输出结果

g1 :

--------------------

现在定义了a变量

1

现在又定义了b变量

2

生成器有什么好处呢?就是不会一下子在内存中生成太多数据

def produce():

"""生产衣服"""

for i in range(2000000):

yield "生产了第%s件衣服"%i

product_g = produce()

print(product_g.__next__()) #要一件衣服

print(product_g.__next__()) #再要一件衣服

print(product_g.__next__()) #再要一件衣服

num = 0

for i in product_g: #要一批衣服,比如5件

print(i)

num +=1

if num == 5:

break

#到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。

#剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿

def produce():

"""生产衣服"""

for i in range(2000000):

yield "生产了第%s件衣服"%i

product_g = produce()

print(product_g.__next__()) #要一件衣服

print(product_g.__next__()) #再要一件衣服

输出结果

生产了第0件衣服

生产了第1件衣服

生成器本质也是一个迭代器,当我们一次次的索要产生的值时,,每次遇到yield就会停止一下,返回值和生成结果,再次索要下次的值时就会重复的进行相同的操作。

def produce():

"""生产衣服"""

for i in range(2000000):

yield "生产了第%s件衣服"%i

product_g = produce()

print(product_g.__next__()) #要一件衣服

# print(product_g.__next__()) #再要一件衣服

# print(product_g.__next__()) #再要一件衣服

# print(product_g.__next__()) #再要一件衣服

# print(product_g.__next__()) #再要一件衣服

# print(product_g.__next__()) #再要一件衣服

# print(product_g.__next__()) #再要一件衣服

num = 0

for i in product_g: #要一批衣服,比如5件

print(i)

num +=1

if num == 5:

break

输出结果

生产了第0件衣服

生产了第1件衣服

生产了第2件衣服

生产了第3件衣服

生产了第4件衣服

生产了第5件衣服

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值