python中一切皆对象,函数也是,用def或者lambda创建时,便获得个函数对象。在函数对象中保存着一些函数的元数据,例如:
f.__name__ :函数的名字
f.__doc__ :函数文档字符串
f.__moudle__ :函数所属模块名
f.__dict__ :属性字典
f.__defaults__ :默认参数元组
...
在使用装饰器后,再使用上面这些属性访问时,看到的是内部包裹函数的元数据,原来函数的元数据便丢失了
def f(a):
'''f function'''
return a * 2
f.
f.__name__
g = f
g.__name__ # f ; 函数定义的时候就赋的值
f.__doc__ # ‘f function’
f.__module__ # __main__ ; 函数属于模块,当前函数不是导入的,在__main__里
f.__defaults__
def f(a,b=1,c=[]):
print a,b,c
f.__defaults__ # (1,[]) ; 保存函数默认参数,在python中,不是每次调用创建;而是定义函数时,直接创建好
f(100)
f.__defaults__[1].append('abc') # 100,1,['abc'] ; 在默认参数中,尽量不要使用可变对象
f.__closure__
def f():
a = 2
return lambda k: a ** k
# 存在一个闭包;在f()函数退出以后,之后的lambda还可以访问a
g = f()
c = g.__closure__[0]
c.cell_contents # 2
#
def mydecorator(func):
def wrapper(*args, **kargs):
'''wrapper function'''
print 'In wrapper'
func(*args, **kargs)
return wrapper
@mydecorator # 装饰后,example函数变成wrapper函数
def example():
'''example function'''
print 'In example'
print example.__name__ # wrapper
print example.__doc__ # wrapper function
# 但wrapper中内部数据无用,应保留example中的原数据
# 使用标准库functools中的装饰器wraps装饰内部包裹函数,可以制定将原函数的某些属性,更新到包裹函数上
from functools import update_wrapper, wraps, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES
def mydecorator(func):
def wrapper(*args, **kargs):
'''wrapper function'''
print 'In wrapper'
func(*args, **kargs)
# wrapper.__name__ = func.__name__ ; 不优雅
#update_wrapper(wrapper,func,('__name__','__doc__'),('__dict__',))
update_wrapper(wrapper,func)
return wrapper
@mydecorator
def example():
'''example function'''
print 'In example'
print example.__name__ # example
print example.__doc__ # example function
#print WRAPPER_ASSIGNMENTS # updata_wrapper的默认第3个参数
#print WRAPPER_UPDATES # updata_wrapper的默认第4个参数
wraps是一个函数,所以可以当装饰器直接装饰
from functools import update_wrapper, wraps, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES
def mydecorator(func):
@wraps(func)
def wrapper(*args, **kargs):
'''wrapper function'''
print 'In wrapper'
func(*args, **kargs)
return wrapper
@mydecorator
def example():
'''example function'''
print 'In example'