一.装饰器
1.知识储备
函数对象
函数可以被引用
函数可以当参数传递
返回值可以是函数
可以当作容器的元素
def func1(): print (666) def func2(): print (666) def func3(): print (666) list1=[func1,func2,func3] for i in list1: i()
*args:接收溢出的位置参数
**kwargs:接收溢出的关键字参数
名称空间与作用域
2.闭包函数
闭包函数的定义:定义在函数内部的函数,特点是:包含对外部作用域而不是全局作用域名字的引用。这个函数就称为闭包函数。
闭包函数的两个特征:内部函数要引用外部函数的变量,外部函数的返回值是内部函数。
例子:
当函数内部需要一个变量的时候,有两种方式给函数传入变量,
第一种:为函数添加一个参数。
第二种:把这个函数变成闭包函数,也就是在函数外部添加一个函数。把变量写在外部函数内,或者当作参数传给外部函数。将内部函数的函数名return一下,这样内部函数就被外部函数包起来了。
闭包特性:python遇到闭包,不会释放名称空间。
3.装饰器
为什么要用装饰器?
开放封闭原则:对扩展是开放的,对修改是关闭的
1. 不修改被装饰对象的源代码 2. 不修改被装饰对象的调用方式。
装饰器的目标:在遵循1和2的前提下,为被装饰器对象添加上新功能
什么是装饰器?
装饰他人的器具,本身可以任意可调用对象,被装饰者也可以是任意可调用对象。
带参数的装饰器,怎么写?
4.练习题:
一,编写函数,(函数的执行时间是随机的)
import time def a(): x = time.strftime('%Y-%m-%d %X') print(x) a()
结果:
D:\Python36\python.exe F:/python/第一课/while-lianxi.py
2017-10-14 08:40:11
二,编写装饰器,为函数加上统计时间的功能。
#这种是采用传参的方式,虽然没有修改index和home函数的源代码,但是修改了它们的调用方式。所以需要采用装饰器。
import time
def timmer(tongji_hanshu):
# tongji_hanshu=home
def inner():
start_time=time.time()
tongji_hanshu()
stop_time=time.time()
print("函数执行时间: %s" %(stop_time-start_time))
return inner
@timmer #语法糖
def index():
time.sleep(3)
print("welcome to index page!")
index()
@timmer
def home():
time.sleep(5)
print("welcome to home page!")
home()
结果:
D:\Python36\python.exe F:/python/第一课/while-lianxi.py
welcome to index page!
函数执行时间: 3.0001718997955322
welcome to home page!
函数执行时间: 5.000285863876343
三. 编写装饰器,为函数加上认证的功能。
import time def outter(func): def auth(): username=input("输入用户名: ").strip() password=input("输入密码: ").strip() if username=='yangjianbo' and password=='123': print ("登录成功!") func() #这么写死了 else: print("登录失败!") return auth @outter def index(): time.sleep(3) print("welcome to index page!") index()
结果:
D:\Python36\python.exe F:/python/第一课/while-lianxi.py
输入用户名: yangjianbo
输入密码: 123
登录成功!
welcome to index page!
四:编写装饰器,为多个函数加上认证功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码。
#这种情况是针对index,没有参数的函数,如果被装饰的函数有参数,如何修订装饰器。 import time def outter(func): def auth(*args,**kwargs): username=input("输入用户名: ").strip() password=input("输入密码: ").strip() if username=='yangjianbo' and password=='123': print ("登录成功!") func(*args,**kwargs) #这么写死了 else: print("登录失败!") return auth @outter def index(): time.sleep(3) print("welcome to index page!") index() @outter #home=outter(home) def home(username): time.sleep(2) print("welcome %s to home page!" %username) home('yangjianbo')
结果:
D:\Python36\python.exe F:/python/第一课/while-lianxi.py
输入用户名: yangjianbo
输入密码: 123
登录成功!
welcome to index page!
输入用户名: yangjianbo
输入密码: 123
登录成功!
welcome yangjianbo to home page!
根据题目要求:只要登录成功,以后就不需要再登录。所以上面的代码还需要修改。
import os import time login_status=False def outter(func): def auth(*args,**kwargs): if login_status is True: return func(*args,**kwargs) else: username=input("输入用户名: ").strip() password=input("输入密码: ").strip() with open('account.txt','r',encoding='utf-8') as accout: accout=accout.read().strip('\r\n').split('|') if username==accout[0] and password==accout[1]: print ("登录成功!") login_status=True func(*args,**kwargs) else: print("登录失败!") return auth @outter #index=outter(index) def index(): time.sleep(3) print("welcome to index page!") index() @outter def home(username): time.sleep(2) print("welcome %s to home page!" %username) home('yangjianbo')
结果:
D:\Python36\python.exe F:/python/第一课/while-lianxi.py
Traceback (most recent call last):
File "F:/python/第一课/while-lianxi.py", line 158, in <module>
index()
File "F:/python/第一课/while-lianxi.py", line 140, in auth
if login_status is True:
UnboundLocalError: local variable 'login_status' referenced before assignment
上面报错的分析:说局部变量login_status在引用之前没有指定.
我明明定义在全局作用域了,为什么报错?
解决方法:在函数内,添加一个关键字global,表示引用全局变量。
修改后的代码:
import os import time login_status=False def outter(func): def auth(*args,**kwargs): global login_status if login_status is True: return func(*args,**kwargs) else: username=input("输入用户名: ").strip() password=input("输入密码: ").strip() with open('account.txt','r',encoding='utf-8') as accout: accout=accout.read().strip('\r\n').split('|') if username==accout[0] and password==accout[1]: print ("登录成功!") login_status=True func(*args,**kwargs) else: print("登录失败!") return auth @outter #index=outter(index) def index(): time.sleep(3) print("welcome to index page!") index() @outter def home(username): time.sleep(2) print("welcome %s to home page!" %username) home('yangjianbo')
结果:没有报错了。
第四个装饰器最后版本:
import time user_status={"user":None,"login_status":False} def outter(func): def auth(*args,**kwargs): if user_status['user'] and user_status['login_status']: res=func(*args, **kwargs) return res username=input("输入用户名: ").strip() password=input("输入密码: ").strip() if username=='yangjianbo' and password=='123': print ("登录成功!") user_status['user']=username user_status['login_status']=True res=func(*args, **kwargs) return res else: print("登录失败!") return auth @outter def index(): time.sleep(3) print("welcome to index page!") # return 123 index() @outter def home(username): time.sleep(2) print("welcome to %s home page" % username) # return 456 home('yangjianbo')
练习五 编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录
import time import random user={"user":None,"login_time":None,'timeout':0.03} def timmer(func): def inner(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('%s' %(stop_time-start_time)) return res return inner def outter(func): def auth(*args,**kwargs): if user['user']: timeout=time.time()-user['login_time'] if timeout<user['timeout']: res=func(*args, **kwargs) return res username=input("输入用户名: ").strip() password=input("输入密码: ").strip() if username=='yangjianbo' and password=='123': user['user']=username user['login_time']=time.time() res=func(*args, **kwargs) return res else: print("登录失败!") return auth @outter def index(): time.sleep(random.randrange(3)) print("welcome to index page!") index() @outter def home(username): time.sleep(random.randrange(3)) print("welcome to %s home page" % username) home('yangjianbo')
练习六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
from urllib.request import urlopen def outer(url): def get(): f=urlopen(url).read() return f return get baidu=outer('http://www.baidu.com') sohu=outer('http://www.sohu.com') baidu=baidu() sohu=sohu()
练习七:拿到下载的页面,保存到一个文件中。
from urllib.request import urlopen def outer(url): def get(): f=urlopen(url).read() return f return get baidu=outer('http://www.baidu.com') sohu=outer('http://www.sohu.com') baidu=baidu() sohu=sohu() with open('baidu.html','w',encoding='utf-8') as f: f.write(baidu.decode('utf-8'))
六. 迭代器
可迭代对象
内部含有'__iter__'方法的数据就是可迭代对象
s1='abcdef'
print (dir(s1))
print('__iter__' in dir(s1))
迭代器对象
内部含有'__iter__'方法并且含有'__next__'方法就是迭代器
如何将可迭代对象转换为迭代器对象
list1=[1,2,3,4]
iter1=iter(list1) #可迭代对象转换为迭代器
print(iter1)
print(iter1.__next__())
迭代器的特点
1. 非常节省内存
2. 他满足惰性机制
3. 一条走到黑
利用while循环模拟for循环
list1=[1,2,3,4]
iter1=iter(list1)
while 1:
try:
print(iter1.__next__())
except StopIteration:
break
七. 生成器
自己用python代码写的迭代器
生成器的定义:
1. 函数式写法,构建生成器
2. 只要函数中出现yield,那么他就不是函数了,它是生成数函数。
八.列表推导式
凡是用列表推导式构建的数据,python代码都可以构建,列表推导式都可以构建。
循环模式
list1=[i for i in range(1,200)]
print (list1)
筛选模式
九.生成器表达式
十.列表推导式与生成器表达式
优点:构造简单,一行完成。
缺点:不能排错
不能构建复杂的数据结构