装饰器
装饰器decorator 是我之前一直很难懂的地方,曾经想死记装饰器的写法,但不得要领。现在,自己又实现了一次装饰器的编写,发现并没有那么难懂呢。发现,其实,它跟js的闭包非常的像。甚至说一致,然后再加上一个f=myfnc(f)的作用域替换。
所以,装饰器模式,首先能闭包,即函数内能继续嵌套定义函数,内部的函数,享受外部作用域的变量值。另外,有一种方便的方式,覆盖原函数。
关于理解:从调用的方式来看,最外层的函数,最先调用。最内部的函数,是最后调用,而且是跟原函数一样的参数结构。每调用一次,脱一层。所以,理论上讲,能嵌套很多层,视具体情况而定。从最终调用的函数,即定义在最内部的函数来看,它可能需要很多参数,在本层解决不了,那么,没有关系,我们可以在最外边加一层,一层不行,加二层,反正其他层的变量,在此都是生效的,都是为了本层服务的。(其实,这也是自己理解js的闭包层层封装,js是方便,生成各种的调用方法)(js理论上讲也容易实现装饰器方式,只是没有@那种语法)。
正文
带参数和不带参数
以下实现,带参、不带参均可调用的装饰器,高明之处,是对调用的参数进行判断。(当然也可以不准)
def log(text=None):
if isinstance(text, str):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
else:
@functools.wraps(text)
def wrapper(*args, **kw):
print('call %s():' % text.__name__)
return text(*args, **kw)
return wrapper
示例1
代码中需要将数据插入到数据库中,但是下面的函数结构基本上都是固定的,这个时候,改为装饰器的方式进行封装,减少无用的代码使用。参考来源:python教程
def save(table_name,primary_key='projectname'):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
row = func(*args, **kw)
data,db,path = args
try:
item = db.one(table_name,'projectname','where '+ primary_key + ' = %s',[data.projectname])
if item:
projectname = item[0]
print('更新 ' + table_name)
db.update(table_name,row,'projectname = %s',[projectname])
else:
print('插入 ' + table_name)
db.insert(table_name,row)
except Exception as e:
print('插入或更新失败:%s %s'%(data.projectname,e))
return wrapper
return decorator
调用时:
效果,直接将返回的数据,插入到数据库的表中。
@save('git_summary')
def save_sumarry(data,db,path):
return {
'projectname':data.projectname,
'first_commit':data.getFirstCommitDate().strftime(format),
}
warp的参数,也可以如实写成跟原函数一样的形式,
def wrapper(data,db,path ):
row = func(data,db,path )