9-2 如何为被装饰的函数保存元数据

在python中一切皆对象,函数也是对象,在使用def或lamda创建函数时,就得到了函数对象。

定义一个简单的函数,再查看一下它有哪些元数据
1、函数的名字
>>> f.func_name 'f' >>> f.__name__ 'f' >>>
这个名字是函数对象的名字。和引用函数的变量名无关。它是在创建时写入对象的名字的
>>> g = f >>> g.func_name 'f' >>> g.__name__ 'f' >>>
2、函数的字符串文档
>>> f.__doc__ 'f function' >>> f.func_doc 'f function' >>>
3、函数所属的模块
>>> f.__module__ '__main__'
因为这个函数不是模块导入的,在本模块中,所以是__main__模块
4、函数的默认参数
>>> f.func_defaults >>> f.__defaults__ >>>
在这个函数里是空的,没有默认参数。
重新定义一个函数
>>> def f_test(a,b=1,c=[]): print a,b,c >>> f_test.func_defaults (1, []) >>> f_test.__defaults__ (1, []) >>>
说明默认参数不是在调用时才创建并赋值的,而是在定义时就已经创建好了。
在调用前修改一下默认参数的值
>>> f_test.__defaults__[0]=5 Traceback (most recent call last): File "<pyshell#27>", line 1, in <module> f_test.__defaults__[0]=5 TypeError: 'tuple' object does not support item assignment
注意这里说tuple不允许修改,然后我们修改tuple里面的列表的值
>>> f_test.__defaults__[1].append('abc')
调用时

>>> f_test(10) 10 1 ['abc']
所以默认参数时,尽量不要使用可变对象。
5、查看函数的闭包
>>> f.func_closure >>> f.__closure__ >>>
f函数是没有的,返回空None
再重新定义一下f()函数
>>> def f(): a = 2 return lambda k:a**k
这里不会,因为f()函数的退出,lambda函数就访问不了a,因为形成了闭包。f()函数,返回了lambda函数
>>> g = f() #g相当于lambda函数 >>> g.__closure__ (<cell at 0x027949F0: int object at 0x0219B5DC>,) >>> c = g.__closure__[0] >>> c <cell at 0x027949F0: int object at 0x0219B5DC> >>> c.cell_contents 2 >>> f() <function <lambda> at 0x02796B30> >>> g <function <lambda> at 0x027AC9F0> >>> g(2) 4 >>> f()(2) 4 >>> f()(3) 8
使用装饰器会修改函数的元属性
def mydecorator(func): #装饰器,本例没增加功能,只做为演示 def wrapper(*args,**kargs): """wrapper function""" print 'In wrapper' func(*args,**kargs) return wrapper def example(): """example function""" print 'In example' print example.__name__ print example.__doc__
输出结果:
example
example function
使用装饰器后
@mydecorator def example(): """example function""" print 'In example' print example.__name__ print example.__doc__
输出结果:
wrapper
wrapper function
优化方法一:
from functools import update_wrapper,wraps def mydecorator(func): def wrapper(*args,**kargs): """wrapper function""" print 'In wrapper' func(*args,**kargs) update_wrapper(wrapper,func) #第一个参数是包裹函数,第二个参数是被包裹函数,其他参数使用默认值 return wrapper @mydecorator def example(): """example function""" print 'In example' print example.__name__ print example.__doc__
输出结果:
example
example function
优化方法二:
from functools import update_wrapper,wraps def mydecorator(func): @wraps(func) #wraps是装饰器,带有参数,第一个参数是被包裹的函数,其他参数默认 def wrapper(*args,**kargs): """wrapper function""" print 'In wrapper' func(*args,**kargs) #update_wrapper(wrapper,func) #第一个参数是包裹函数,第二个参数是被包裹函数,其他参数使用默认值 return wrapper @mydecorator def example(): """example function""" print 'In example' print example.__name__ print example.__doc__
输出结果:
example
example function
posted on 2018-05-09 16:29 石中玉smulngy 阅读(147) 评论(0) 收藏 举报
浙公网安备 33010602011771号