https://www.cnblogs.com/linhaifeng/articles/7532497.html
https://www.cnblogs.com/linhaifeng/articles/6140395.html
一.装饰器
1.本质就是函数/类,用于修饰其他函数(添加附加功能)
2.原则:不修改被修饰函数的源代码/调用方式(开放封闭原则:对扩展开放,对修改封闭)(修改后后果未知)
3.知识储备:装饰器=高阶函数+函数嵌套+函数闭包
4.语法:被装饰函数的正上方,单独一行
import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print("函数运行时间是%s"%(stop_time-start_time))
return res
return wrapper
@timmer
def cal(li):
res=0
for i in li:
time.sleep(0.1)
res+=i
return res
a=cal(range(20))
print(a)
#结果为:函数运行时间是2.0001144409179688
# 190
5.基本实现:
import time
#装饰器框架
def timmer(func):
def wrapper(name,age):
#print(func)
start_time=time.time()
res=func(name,age) #在运行test
stop_time=time.time()
print("运行时间是%s"%(stop_time-start_time))
return res
return wrapper
def test(name,age):
print("我是%s,今年%s岁"%(name,age))
return "test的返回值"
test=timmer(test) #返回的是wrapper的地址
test("alex",18) #实际运行的是timmer的返回值wrapper
6.使用可变长参数与语法糖:
语法糖:@timmer相当于test=timmer(test),位于要修饰的函数前边,单独占一行
def timmer(func):
def wrapper(*args,**kwargs):
#print(func)
start_time=time.time()
res=func(*args,**kwargs) #在运行test
stop_time=time.time()
print("运行时间是%s"%(stop_time-start_time))
return res
return wrapper
@timmer
def test1(name,age):
print("我是%s,今年%s岁"%(name,age))
return "test的返回值"
@timmer
def test2(name,age,gender):
print("我是%s,今年%s岁,是%s性"%(name,age,gender))
return "test的返回值"
test1("alex",18)
test2("alex",18,"男")
7.使用:
#无参装饰器=函数嵌套+高阶函数:
import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
@timmer
def foo():
time.sleep(3)
print('from foo')
foo()
#有参装饰器:
def auth(driver='file'):
def auth2(func):
def wrapper(*args,**kwargs):
name=input("user: ")
pwd=input("pwd: ")
if driver == 'file':
if name == 'egon' and pwd == '123':
print('login successful')
res=func(*args,**kwargs)
return res
elif driver == 'ldap':
print('ldap')
return wrapper
return auth2
@auth(driver='file')
def foo(name):
print(name)
foo('egon')
8.超时装饰器
import sys,threading,time
class KThread(threading.Thread):
"""A subclass of threading.Thread, with a kill()
method.
Come from:
Kill a thread in Python:
http://mail.python.org/pipermail/python-list/2004-May/260937.html"""
def __init__(self, *args, **kwargs):
threading.Thread.__init__(self, *args, **kwargs)
self.killed = False
def start(self):
"""Start the thread."""
self.__run_backup = self.run
self.run = self.__run # Force the Thread to install our trace.
threading.Thread.start(self)
def __run(self):
"""Hacked run function, which installs the trace."""
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, why, arg):
if why == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, why, arg):
if self.killed:
if why == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
self.killed = True
class Timeout(Exception):
"""function run timeout"""
def timeout(seconds):
"""超时装饰器,指定超时时间
若被装饰的方法在指定的时间内未返回,则抛出Timeout异常"""
def timeout_decorator(func):
"""真正的装饰器"""
def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):
result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))
def _(*args, **kwargs):
result = []
new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list
'oldfunc': func,'result': result, 'oldfunc_args': args,'oldfunc_kwargs': kwargs}
thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)
thd.start()
thd.join(seconds)
alive = thd.isAlive()
thd.kill() # kill the child thread
if alive:
raise Timeout(u'function run too long, timeout %d seconds.' % seconds)
else:
return result[0]
_.__name__ = func.__name__
_.__doc__ = func.__doc__
return _
return timeout_decorator
@timeout(5)
def method_timeout(seconds, text):
print('start', seconds, text)
time.sleep(seconds)
print('finish', seconds, text)
return seconds
method_timeout(6,'asdfasdfasdfas')
9.wraps:
from functools import wraps
def deco(func):
@wraps(func) #加在最内层函数正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper
@deco
def index():
'''哈哈哈哈'''
print('from index')
print(index.__doc__)
10.叠加多个装饰器:
加载顺序(outter函数的调用顺序):自下而上
执行顺序(wrapper函数的执行顺序):自上而下
def outter1(func1): #func1=wrapper2的内存地址
print('加载了outter1')
def wrapper1(*args,**kwargs):
print('执行了wrapper1')
res1=func1(*args,**kwargs)
return res1
return wrapper1
def outter2(func2): #func2=wrapper3的内存地址
print('加载了outter2')
def wrapper2(*args,**kwargs):
print('执行了wrapper2')
res2=func2(*args,**kwargs)
return res2
return wrapper2
def outter3(func3): # func3=最原始的那个index的内存地址
print('加载了outter3')
def wrapper3(*args,**kwargs):
print('执行了wrapper3')
res3=func3(*args,**kwargs)
return res3
return wrapper3
@outter1 # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址
@outter2 # outter2(wrapper3的内存地址)======>wrapper2的内存地址
@outter3 # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址
def index():
print('from index')
print('===')
index()
二.高阶函数的使用
参数为函数-----可不修改源代码,会改变被修饰函数调用方式:
import time
def foo():
print("a")
def test(func):
start_time=time.time()
func()
stop_time=time.time()
print("函数运行时间是%s"%(stop_time-start_time))
test(foo)
返回值是函数-----可不更改调用方式,会修改源代码:
import time
def foo():
print("a")
def test(func):
return func
foo=test(foo)
foo()
二者结合-----foo()运行了2遍:
import time
def foo():
print("a")
def timmer(func):
start_time=time.time()
func()
stop_time=time.time()
print("函数运行时间是%s"%(stop_time-start_time))
return func
foo=timmer(foo)
foo()
三.函数闭包
1.闭包:在一个作用域里放入定义
一个闭包内是一个作用域
2.意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
3.应用:延迟计算(原来是传参,现在是包起来)
from urllib.request import urlopen
def index(url):
def get():
return urlopen(url).read()
return get
baidu=index('http://www.baidu.com')
print(baidu().decode('utf-8'))
四.解压序列:
l=[1,23,4,54,3,54,2,37,19,12,3,45]
a,*_,b=l #a为1,b为45,_为[23,4,54,3,54,2,37,19,12,3]
#_也可换为任何非空字符
c,d,*_,e,f=l #c为1,d为23,e为3,f为45
*_,g=l #g为45