第四章:Python的装饰器+迭代器+生成器+三元表达式+列表解析+生成器表达式
大纲:
Python装饰器:
闭包函数
迭代器
三元表达式
列表解析
生成器表达式
Python的装饰器
讲Python的装饰器之前一定要理解毕包函数,什么叫毕包函数:
毕包函数
python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).这个定义是相对直白的,好理解的,不像其他定义那样学究味道十足(那些学究味道重的解释,在对一个名词的解释过程中又充满了一堆让人抓狂的其他陌生名词,不适合初学者)。
#闭包函数:
#1. 定义在函数内部的函数
#2. 包含对外部作用域名字的引用,而不是对全局作用域名字的引用
#那么该内部函数就称为闭包函数
下面举一个简单的例子来说明。
#毕包函数 def deco(): x=123123123123 def wrapper(): #wrapper就是毕包函数 print(x) return wrapper func=deco() func()
#闭包函数的应用:惰性计算
#闭包函数的应用:惰性计算 # import requests # def get(url): # return requests.get(url).text import requests def index(url): def get(): print(requests.get(url).text) return get boke_web=index('http://www.cnblogs.com/sheng-247/articles/7225975.html') baidu_web=index('https://www.baidu.com/') boke_web() baidu_web()
总结:
#大前提:作用域关系,在函数定义时就已经固定
# ,与调用位置无关,在调用函数时,必须必须必须
#回到函数原来定义的位置去找作用域关系
毕包函数的应用
==》无参数装饰器和有参装饰器
#1 开放封闭原则:对扩展是开放的,对修改是封闭
#2 装饰器:装饰它人的工具,
#装饰器本身可以是任意可调用对象,被装饰的对象本身也可以是任意可调用对象
1、装饰器的遵循的原则:1 不修改被装饰对象的源代码 2 不修改被调用对象的调用方式
2、装饰器的目的是:在遵循1和2原则的前提,为其他新功能函数添加
#@装饰器名,必须写在被装饰对象的正上方,并且是单独一行
无参数装饰器
1、毕包函数应用装饰器(计算函数运行时间)
#装饰器(无参数装饰器) import time def timer(fun): def wrapper(): start_time=time.time() fun() stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return wrapper @timer #func=timer(func) 必须写在被装饰对象的正上方,并且是单独一行 def func(): time.sleep(0.3) print('from func ~~') @timer #home=timer(home) def home(): time.sleep(0.5) print('from home ~~') func() home()
2、装饰器的修饰
当被装饰额函数有参数的时候装饰器的用法:
import time def timer(fun): def wrapper(*args,**kwargs): start_time=time.time() res=fun(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper @timer #func=timer(func) def func(): time.sleep(0.3) print('from func ~~') return 123 @timer #home=timer(home) def home(name): time.sleep(0.5) print('from home %s ~~'%name) func() home('lele')
3、 实现认证功能装饰器(用户登录装饰器)
#用户登录装饰(简洁版本) crrent_user={'user_name':None} def auto(fun): def wrapper(*args,**kwargs): if crrent_user['user_name']: fun() else: user_name=input('user_name>>').strip() passwd=input('passwd>>').strip() if user_name == 'sheng' and passwd == '123': crrent_user['user_name']=user_name fun(*args,**kwargs) else: print('user_name or passwd error !') return wrapper @auto def home(): print('from home') @auto def index(): print('from index') home() index()
4、实现认证功能装饰器(在文件中去用户密码判断)
#用户登录装饰(当用户密码 判断用户那种类型在登录) crrent_user={'user_name':None} def auto(fun): def wrapper(*args,**kwargs): if crrent_user['user_name']: fun() else: user_name=input('user_name>>').strip() passwd=input('passwd>>').strip() with open('auth.txt','r',encoding='utf-8') as read_f: user_data=eval(read_f.read()) if user_name in user_data and passwd == user_data[user_name]: crrent_user['user_name']=user_name fun(*args,**kwargs) else: print('user_name or passwd error !') return wrapper @auto def home(): print('from home') @auto def index(): print('from index') home() index()
有参装饰器
5、实现认证功能装饰器(判断用户那种类型在登录)
#用户登录装饰(基于用户登录类型 判断用户那种类型在登录) crrent_user={'user_name':None} def Auth(user_type='file'): def auto(fun): def wrapper(*args,**kwargs): if user_type == 'file': if crrent_user['user_name']: fun() else: user_name=input('user_name>>').strip() passwd=input('passwd>>').strip() with open('auth.txt','r',encoding='utf-8') as read_f: user_data=eval(read_f.read()) if user_name in user_data and passwd == user_data[user_name]: crrent_user['user_name']=user_name fun(*args,**kwargs) else: print('user_name or passwd error !') elif user_type == 'mysql': print('from mysql ....') elif user_type == 'ldap': print('from ldap !!!') else: print('user type error !') return wrapper return auto @Auth(user_type='file') def home(): print('from home') @Auth(user_type='mysql') def index(): print('from index') home() index()
迭代器
定义:#迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来
#什么是迭代器对象:
1、 有__iter__,执行得到仍然是迭代本身
2、有__next__
#可迭代对象iterable:凡是对象下有__iter__方法:对象.__iter__,该对象就是可迭代对象
#迭代器对象:可迭代对象执行内置的__iter__方法,得到的结果就是迭代器对象
可迭代对象(Iterable)
Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,像常见的list,tuple都是。如果给一个准确的定义的话,就是只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下标索引的__getitem__方法(这些双下划线方法会在其他章节中全面解释),那么它就是一个可迭代对象。
迭代器(iterator)
迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义了这个方法的都算是迭代器。可以用通过下面例子来体验一下迭代器:
s='hello' l=['a','b','c','d'] t=('a','b','c','d') dic={'name':'egon','sex':'m',"age":18} set1={1,2,3} f=open('db.txt') s.__iter__() l.__iter__() t.__iter__() dic.__iter__() set1.__iter__() f.__iter__()
一般数据类型都是迭代器对象。
迭代器对象的优点
1、:提供了一种统一的(不依赖于索引的)迭代方式
2、:迭代器本身,比起其他数据类型更省内存,同一时间只有一个值在内存之中
迭代器对象的缺点
1、:一次性,只能往后走,不能回退,不如索引取值灵活
2、:无法预知什么时候取值结束,即无法预知长度
a=['a','c','d','e','f'] iter_a=iter(a) #无法预知什么时候取值结束,即无法预知长度,需要抛出异常 while True: try: print(next(iter_a)) except StopIteration: break
迭代器的例子:
for i in l: #l=l.__iter__() for循环就是利用迭代器的原理来使用 print(i)
with open('db.txt','r',encoding='utf-8') as read_f: print(read_f is read_f.__iter__()) #文件read_f本身就是迭代器 #True
补充:判断可迭代对象与迭代器对象(了解)
from collections import Iterable,Iterator s='hello' l=['a','b','c','d'] t=('a','b','c','d') dic={'name':'egon','sex':'m',"age":18} set1={1,2,3} f=open('a.txt') # print(isinstance(s,Iterable)) # print(isinstance(l,Iterable)) # print(isinstance(t,Iterable)) # print(isinstance(dic,Iterable)) # print(isinstance(set1,Iterable)) # print(isinstance(f,Iterable)) print(isinstance(s,Iterator)) print(isinstance(l,Iterator)) print(isinstance(t,Iterator)) print(isinstance(dic,Iterator)) print(isinstance(set1,Iterator)) print(isinstance(f,Iterator)) False False False False False True
生成器
生成器(generator)
生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()和__next__()方法了,只需要一个yiled关键字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值。用生成器来实现斐波那契数列的例子是:
生成器
#生成器:在函数内部包含yield关键,那么该函数执行的结果是生成器
#生成器就是迭代器
def func(): print('first') yield 11111111 print('second') yield 2222222 print('third') yield 33333333 print('fourth') g=func() #g就是一个生成器,也就是一个迭代器 print(g is g.__iter__()) #True for i in g: print(i) print('============>')
生成器generator的作用:
def fun(n): print('开始了~') while True: yield n n+=1 g=fun(0) for i in g: #可以产生无穷无尽的值 print(i)
def my_range(start,stop): while True: if start == stop: raise StopIteration #自动抛出异常 yield start start +=1 g=my_range(1,3) for i in my_range(1,5): print(i)
#yield的功能:
# 1 把函数的结果做生迭代器(以一种优雅的方式封装好__iter__,__next__)
# 2 函数暂停与再继续运行的状态是由yield
yield生产器的应用:
模仿linux命令grep功能:
# yield生产器的应用命令grep: import time def tailf(filepath): with open(filepath,'r') as read_f: read_f.seek(0,2) while True: line= read_f.readline() if line: yield line else: time.sleep(0.2) def grep(word,lines): for i in lines: if word in i: print(i,end='') grep('error',tailf('db.txt')) ###################往文件里面写################## with open('db.txt','a',encoding='utf-8') as write_f: write_f.write('12eerrorddddr2\n')
三元表达式
# def max(x,y): # if x>y: # return x # else:return y x=12 y=23 print(x) if x>y else print(y) #三元表达式
列表解析
在一个序列的值上应用一个任意表达式,将其结果收集到一个新的列表中并返回。它的基本形式是一个方括号里面包含一个for语句对一个iterable对象迭代。
l=[] for i in range(10): l.append('egg%s'%i) print(l) #列表解析 l=['egg%s' %i for i in range(10)] print(l) ['egg0', 'egg1', 'egg2', 'egg3', 'egg4', 'egg5', 'egg6', 'egg7', 'egg8', 'egg9'] ['egg0', 'egg1', 'egg2', 'egg3', 'egg4', 'egg5', 'egg6', 'egg7', 'egg8', 'egg9'] l=['egg%s' %i for i in range(10) if i >5 ] print(l) ['egg6', 'egg7', 'egg8', 'egg9']
l=[] for i in range(10): if i>5: l.append('egg%s'%i) print(l) l=['egg%s' %i for i in range(10) if i >5 ] print(l)
练习:
把列表[1,2,3,4,5]都变成平方:
a=[1,2,3,4,5,6] a=[i**2 for i in a] print(a) a=[1,2,3,4,5,6] a_2=[i**2 for i in a if i >3] print(a_2) [1, 4, 9, 16, 25, 36] [16, 25, 36]
生成器表达式
生成器(generator)概念
生成器语法
生成器表达式: 通列表解析语法,只不过把列表解析的[]换成()
生成器表达式能做的事情列表解析基本都能处理,只不过在需要处理的序列比较大时,列表解析比较费内存。
生成器表达式
g=['agg%i' %i for i in range(10)] #列表解析 print(g) ['agg0', 'agg1', 'agg2', 'agg3', 'agg4', 'agg5', 'agg6', 'agg7', 'agg8', 'agg9'] g=('agg%i' %i for i in range(10)) #生成器表达式 print(g) #g是一个生成器地址 <generator object <genexpr> at 0x0000000001DE3678> for i in g: print(i) agg0 agg1 ......
练习:
1、统计文本文件最长的一行。
with open('db.txt','r') as read_f: # print(max((len(line) for line in read_f))) print(max(len(line) for line in read_f))
2、文件内容如下,标题为:姓名,性别,年纪,薪资
人 性别 个数 价格
apple 18 3000
computer 38 30000
taoz 28 20000
美女 28 10000
要求统计总量是多少(所有个数*价格的总和)
# with open('apple.txt','r',encoding='utf-8') as read_f: # l=[] # for line in read_f: # line=line.split() # count=int(line[1]) # price=float(line[2]) # l.append(count*price) # print(sum(l)) with open('apple.txt','r',encoding='utf-8') as read_f: l=[int(line.split()[1])*float(line.split()[2]) for line in read_f] print(sum(l))
#把文本文件中的东西放到列表中
with open('apple.txt','r',encoding='utf-8') as read_f: info=[{'name':line.split()[0], 'count':int(line.split()[1]), 'price':float(line.split()[2])} for line in read_f if float(line.split()[2])>3000] print(info)

浙公网安备 33010602011771号