Day12 of learning python--迭代器进阶及生成器

1.*args和**kwargs的使用

调用函数是进行打散操作,函数的行参是聚合操作

1 def outer(*args):  #聚合
2     print(args)            #(1,2,3,4)
3     print(*args)   #打散     # 1,2,3,4
4     def inner(*args):     #传输参数是聚合
5         print('inner:',args)    #inner:(1,2,3,4)
6     inner(*args)   #调用是打散
7 
8 outer(1,2,3,4)  # outer(*[1,2,3,4])  outer(*(1,2,3,4))

 2.readline(),readlines()的区别

readline(),一行一行地读,readlines(),每一行当成列表中地一个元素,添加到List中,且元素后带有换行符‘\n’,‘\r’是回车键的意思

1 f = open('E:\log.txt',mode='r+',encoding='gbk')
2 line = f.readline().strip() #一行一行地读
3 print(line)
4 line = f.readlines()   #每一行当成列表中地一个元素,添加倒list中
5 print(line)

3. wraps的使用

wraps的作用是,因为语法糖的原因,原函数名的func已经不存在于全局了,而是存放了inner的地址了。而wraps是能够重新获取原函数的__doc__,__name__

 1 from functools import wraps
 2 import time
 3 def timmer(f):
 4     @wraps(f)       #没有这个话,原来函数名func已经不存在于全局了,而是存放了inner的地址了
 5     def inner(*args,**kwargs):
 6         start = time.time()
 7         ret = f(*args,**kwargs)
 8         end = time.time()
 9         print(end-start)
10         return ret
11     return inner
12 
13 @timmer
14 def func(a,b):
15     '''
16     这个是问候语
17     :param a:
18     :param b:
19     :return:
20     '''
21     time.sleep(0.01)
22     print('老板好,大家好',a,b)
23     return '新年好'
24 
25 print(func.__name__)   #查看字符串格式的函数名, func
26 print(func.__doc__)    #docunment
27 re = func(1,2)
28 print(re)

 4.装饰器的进阶

装饰器的作用是:在不改变原函数的调用方式的情况下,在函数的请后添加功能,本质是:闭包函数

三层装饰器,应用例子:如果有500个函数,都添加了语法糖,如果要删除这个功能,得一个一个得去删除。但是三层装饰器在外部定义一flag标志符,可以控制装饰器添加的内容不生效

 1 mport time
 2 FLAG = False
 3 def timmer_out(flag):   #用于传入flag
 4     def timmer(func):      # 装饰器
 5         def inner(*args,**kwargs):   #闭包函数,用于装饰功能
 6             if flag:     #如果flag是真的,则执行起到装饰的代码,否则则,执行原函数体
 7                 start = time.time()
 8                 ret = func(*args,**kwargs)
 9                 end = time.time()
10                 print(end-start)
11                 return ret
12             else:
13                 ret = func(*args, **kwargs)
14                 return ret
15         return inner
16     return timmer
17 
18 @timmer_out(FLAG)    #先执行@右边的,timmer_out(FLAG) == timmer @timmer == wahaha =timmer(wahaha)
19 def wahaha():
20     time.sleep(0.1)
21     print('wahahahahahah')
22 
23 @timmer_out(FLAG)
24 def ergoutou():
25     time.sleep(0.1)
26     print('erguotoutoutou')
27 
28 wahaha()
29 ergoutou()

多个装饰器装饰一个函数

 1 def wrapper1(func):  # func -->f
 2     def inner1():
 3         print('wrapper1,before func')
 4         func()
 5         print('wrapper1,after func')
 6     return inner1
 7 
 8 def wrapper2(func): # func -->inner1
 9     def inner2():
10         print('wrapper2,before func')
11         func()
12         print('wrapper2,after func')
13     return inner2
14 
15 @wrapper2    # f = wrapper2(inner1) -->inner2
16 @wrapper1   # f = wrapper1(f) -->inner1
17 def f():
18     print('in f')
19 
20 f()    #inner2()
结果:

wrapper2,before func
wrapper1,before func
in f
wrapper1,after func
wrapper2,after func

 

和俄罗斯的套娃娃一样,注意的是执行的先后顺序

5.生成器

生成器--迭代器

生成器函数--本质上就是自己写的函数

定义:只要含有yield关键字的函数都是生成器函数,而且不能和return公用,二期只能用于函数内部

1 def generator():
2     print(1)
3     yield 'a'
4 #生成器函数:执行之后会得到一个生成器作为返回值,就是一个迭代器
5 ret = generator()
6 print(ret)
7 print(ret.__next__())   #触发生成器的函数体

执行函数体的时候,遇到yield,不会退出函数。

 1 def generator():  #生成器函数
 2     print(1)
 3     yield 'a'
 4     print(2)
 5     yield 'b'
 6     yield 'c'
 7 g = generator()    #g是生成器
 8 # print(g)
 9 # print(g.__next__())
10 # print(g.__next__())
11 # print(g.__next__())
12 for i in g:
13     print(i)    # 一个一个触发yield的返回值
结果:1 a 2 b c

假如我我想定义一个函数,打印200万个哇哈哈,那么一般的方方法会消耗很多的内存资源,用生成器就可以解决了

#娃哈哈%i
def wahaha():
    for i in range(200000):
        yield 'wahahah%s'%i

g = wahaha()

for i in g:     # 一边生成一边打印,打印完了前一个,就不存在于内存当中了
    print(i)

for i in g:
  print(i) #从上个for的yield继续往后面打印

注意,列表是一个迭代对象,但执行多个for的时候,每个for生成的迭代器都是一个新的,不同的

 1 l = [1,2,3,4,5]  # 列表是一个可迭代对象
 2 for i in l:    # 遇到for,在内部转换成一个迭代器
 3     print(i)
 4     if i == 3:
 5         break
 6 
 7 for i in l:    # 重新转换成一个迭代器
 8     print(i)
 9     
10 for i in l:   
11     print(i)

监听文件输入的例子

 1 def tell(filename):
 2     f = open(filename,'r',encoding='gbk')
 3     while True:  # for循环只能读存在的,不能读新写,而且不能操作
 4         line = f.readline()
 5         if line.strip():    # strip(),默认去掉空格,换行符。或者去掉特定字符串
 6             yield line.strip()
 7 
 8 g = tell('F:\hi.txt')    # 该迭代器可以对文件中的内容进行操作
 9 for i in g:
10     print('***',i)

6.作业讲解

1)编写装饰器,为多个函数加上认证的功能(用户的账号和密码来源于文件),要求登陆成功一次,后续的函数都无需再输入用户名和密码

 1 flag = False
 2 def dec(f):
 3     def inner(*args,**kwargs):
 4         global flag       # 在函数内部定义全局变量,让局部函数影响全局变量
 5         if flag == False:
 6             username = input("请输入登陆名:")
 7             password = input("请输入密码:")
 8             with open('F:\hello.txt',mode='r+',encoding='gbk') as file:
 9                 if username == file.readline().strip() and password == file.readline().strip():
10                     flag = True
11                     ret = f(*args, **kwargs)
12                     return ret
13                 else:
14                     print("输入错误")
15         else:
16             ret = f(*args, **kwargs)
17             return ret
18     return inner
19 
20 @dec
21 def shopping_add():
22     print('增加一个物品')
23 
24 @dec
25 def shopping_del():
26     print('删除一个物品')
27 
28 shopping_add()
29 shopping_del()

2)编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件

 1 def remmber(f):
 2     def inner(*args,**kwargs):
 3         ret = f(*args,**kwargs)
 4         with open('F:\hao.txt','a',encoding='gbk') as file:
 5             file.write(f.__name__+'\n')
 6         return ret
 7     return inner
 8 
 9 @remmber
10 def shopping_add():
11     print('增加一个物品')
12 
13 @remmber
14 def shopping_del():
15     print('删除一个物品')
16 
17 shopping_add()
18 shopping_del()
19 with open('F:\hao.txt','r',encoding='gbk') as f1:
20     k = f1.read()
21     print(k)

3)编写下载网页内容的函数,要求功能是:用户传入一个URL,函数返回下载页面的结果,

编写装饰器,实现缓存网页内容的功能,具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载
 1 from urllib.request import urlopen
 2 import os
 3 def cache(f):
 4     def inner(*args,**kwargs):
 5         if os.path.getsize('F:\hello.txt'):
 6             with open('F:\hello.txt', 'rb') as file:
 7                 return file.read()
 8         ret = f(*args,**kwargs)
 9         with open('F:\hello.txt','wb') as file:
10             file.write(b'***'+ret)
11         return ret
12     return inner
13 @cache
14 def get(url):
15     code = urlopen(url).read()  #得到的是一个bytes的代码
16     return code
17 
18 ret = get('http://www.baidu.com')
19 print(ret)
20 ret = get('http://www.baidu.com')
21 print(ret)
22 ret = get('http://www.baidu.com')
23 print(ret)
posted on 2018-09-30 17:12  smile大豆芽  阅读(125)  评论(0)    收藏  举报