软件的设计应该遵循开放封闭原则,即对扩展是开放的,而对修改是封闭的。
软件包含的所有功能的源代码以及调用方式,都应该避免修改,否则一旦改错,则极有可能产生连锁反应,最终导致程序崩溃
装饰
代指为被装饰对象添加新的功能,器
代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。提示:可调用对象有函数,方法或者类,此处我们单以本章主题函数为例,来介绍函数装饰器,并且被装饰的对象也是函数。
函数装饰器分为:无参装饰器和有参装饰两种,二者的实现原理一样,都是’函数嵌套+闭包+函数对象’的组合使用的产物。
import time
def index():
time.sleep(3)
print('Welcome to the index page’)
return 200
index() #函数执行
start_time=time.time()
index() #函数执行
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
def wrapper(func): # 通过参数接收外部的值
start_time=time.time()
res=func()
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
wrapper(index)
wrapper(其他函数)
def timer(func):
def wrapper(): # 引用外部作用域的变量func
start_time=time.time()
res=func()
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
index=timer(index) #得到index=wrapper,wrapper携带对外作用域的引用:func=原始的index
index() # 执行的是wrapper(),在wrapper的函数体内再执行最原始的index
def home(name):
time.sleep(5)
print('Welcome to the home page',name)
home=timer(home)
home('egon')
#抛出异常
TypeError: wrapper() takes 0 positional arguments but 1 was given
egon
)调用的其实是wrapper(egon
),而函数wrapper没有参数。
def timer(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
@timer
@timer
时就会调用timer函数@timer # index=timer(index)
def index():
time.sleep(3)
print('Welcome to the index page')
return 200
@timer # index=timer(home)
def home(name):
time.sleep(5)
print('Welcome to the home page’,name)
@deco3
@deco2
@deco1
def index():
pass
index=deco3(deco2(deco1(index)))
def deco(func):
def wrapper(*args,**kwargs):
编写基于文件的认证,认证通过则执行res=func(*args,**kwargs),并返回res
return wrapper
def deco(func):
def wrapper(*args,**kwargs):
if driver == 'file':
编写基于文件的认证,认证通过则执行res=func(*args,**kwargs),并返回res
elif driver == 'mysql':
编写基于mysql认证,认证通过则执行res=func(*args,**kwargs),并返回res
return wrapper
def auth(driver):
def deco(func):
……
return deco
# 先调用auth_type(driver='file'),得到@deco,deco是一个闭包函数,包含了对外部作用域名字driver的引用,@deco的语法意义与无参装饰器一样
@auth(driver='file')
def index():
pass
@auth(driver='mysql')
def home():
pass
@timer
def home(name):
'''
home page function
:param name: str
:return: None
'''
time.sleep(5)
print('Welcome to the home page',name)
print(help(home))
'''
打印结果:
Help on function wrapper in module __main__:
wrapper(*args, **kwargs)
None
'''
def timer(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
wrapper.__doc__=func.__doc__
wrapper.__name__=func.__name__
return wrapper
from functools import wraps
def timer(func):
@wraps(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