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

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

定义一个简单的函数,再查看一下它有哪些元数据

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)    收藏  举报

导航