python 学习汇总23:装饰器 decorator( tcy)

装饰器 decorator  2018 / 8 / 11
    
==================================================================
1.1.定义:
    # 在代码运行期间动态增加功能的方式,称之为装饰器Decorator
    # decorator是一个返回函数的高阶函数;函数赋值给变量,通过变量调用该函数。
    
==================================================================
1.2.例
    
# 实例1:定义decorator无参数:
import functools
    
def log(func):
    print('装饰器开始...')
    
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print('ready call add...')
        return func(*args, **kwargs)  # 无返回值可省略return
    
    return inner
    
@log  # 相当于add=log(add)
def add(a, b):
    print('runing add...' )
    return a + b
    
#调用
print('a+b= %s' % add(2, 4))
    
#装饰器开始...
#ready call add...
#runing add...
#a+b= 6
    
# 实例2:装饰器输入参数
import functools
    
def log(name='Tom'):
    print('装饰器开始...')
    
    def inner_log(func):
        print('inner_log start...')
    
        def inner(*args, **kwargs):
            inner.__name__ = func.__name__
            print('%s ready call %s...' % (name,inner.__name__))
            return func(*args, **kwargs)
    
        return inner
    
    return inner_log
    

@log('John')  # add = log('John')(add)
def add(a, b):
    print('runing add...')
    return a + b
    
#调用:
print('a+b= %s' % add(2, 4))
    
# 装饰器开始...
# inner_log start...
# John ready call add...
# runing add...
# a+b= 6
    
# 实例3:协程
def coroutine(func):
    def start(*args, **kwargs):
        g = func(*args, **kwargs)
        next(g)
        return g
    
    return start
    
@coroutine
def receiver():
    print('ready to receive')
    while True:
        n = (yield)
        print('got %s' % n)
    
#调用:
r = receiver()
r.send('hello world')
    
#ready to receive
# got hello world
    
===================================================================
2.类装饰器
    
    #装饰器函数是一个接口约束,必须接受callable对象作为参数,返回callable对象。
    #callable对象是函数,对象重写call方法
    
#实例1:无参数类装饰器
class log (object):
    def __init__(self, func):
        print('func name = %s ' % func.__name__)
        self.__func = func
    
    def __call__(self, *args, **kwargs):
        print('装饰器开始...')
        return self.__func(*args, **kwargs)
    
@log
def add(x, y):
    print('runing add...' )
    return x + y
    
#调用:
print('add()=', add(2, 4))
    
#func name = add
#装饰器开始...
#runing add...
#add()= 6
    
#实例2:带参数类装饰器
class log(object):
    def __init__(self, level='INFO'):
        self.level = level
    
    def __call__(self, func):  # 接受函数
        def wrapper(*args, **kwargs):
            print("装饰器{}开始...[ enter function {}()]".format(
                                                                self.level,func.__name__))
            func(*args, **kwargs)
    
        return wrapper  # 返回函数
    

@log('INFO')
def add(x,y):
    print("runing add...[z={}]".format(x+y))
    
#调用:
add(2,3)
    
# 装饰器INFO开始...[ enter function add()]
# runing add...[z=5]
    
=================================================================
3.两个装饰器执行流程
    
def log1(func):
    print('----a----')
    
    def inner(*args, **kwargs):
        print('----1----')
        return ('log1=%s' % func(*args, **kwargs))
    
    return inner
    

def log2(func):
    print('----b----')
    
    def inner(*args, **kwargs):
        print('----2----')
        return ('log2=%s' % func(*args, **kwargs))
    
    return inner
    
@log1
@log2
def add(x, y):
    print('----3----')
    return x + y
    
#调用:
ret = add(2, 4)
print(ret)
    
##输出结果:
#----b----
#----a----
#----1----
#----2----
#----3----
#log1=log2=6
#
"""
说明:
    1)先用第二个装饰器(log2)进行装饰再用第一个装饰器(log1)进行装饰
    调用过程中,先执行第一个装饰器(log1),接着再执行第二个装饰器(log2)。
    
    2)装饰时机
    在执行到 @ log1时,需要对下面的函数进行装饰,此时解释器继续往下走,
    发现并不是一个函数名,而又是一个装饰器,这时@log1装饰器暂停执行 ,
    执行接下来装饰器 @ log2,接着把add函数名传入装饰器函数从而打印’b’
    
    在log2装饰完后此时add指向log2的inner函数地址,这时返回来执行 @ log1
    接着把新add传入log1装饰器函数中,因此打印了’a’。
    
    调用add函数的时候,根据上述分析,此时add指向log1.inner函数,因此会
    先打印‘1‘,接下来,在调用func()的时候,其实是调用的log2.inner()函数,
    所以打印‘2‘,在log2.inner中,调用的func其实才是我们最原声的add函数,
    所以打印原add函数中的‘3‘,所以在一层层调完之后,打印的结果为
    log1 = log2 = 6
"""
=================================================================
4.other
    
4.1.装饰器函数—传递文档说明
def wrap(func):
    def call(*args,**kwargs):
        return func(*args,**kwargs)
    call.__doc__=func.__doc__
    call.__name__=func.__name__
    return call
    
=================================================================
4.2. from functools import wraps
#模块@wraps(func)装饰器可以将属性从func传递给要定义的包装器函数
    
def wrap(func):
    @wraps(func)
    def call(*args,**kwargs):
        return func(*args,**kwargs)
    return call
    
@wrap
def factorial(n):
    """tcy define function used wraps."""
    
# 调用:
help(factorial)
    
# 结果:
# Help on function factorial in module __main__:
# factorial(n)
# tcy define function used wraps.
    
================================================================
4.3.#函数属性
    
def wrap(func):
    def call(*args,**kwargs):
        return func(*args,**kwargs)
    call.__doc__=func.__doc__
    call.__name__=func.__name__
    call.__dict__.update(func.__dict__)
    return call
    
@wrap
def foo():
    'foo function define'
    pass
    
#调用:
foo.secure=1
foo.private=1
help(foo)
print(foo.__dict__)
    
# 结果
'''''''''
Help on function foo in module __main__:
    
foo(*args, **kwargs)
    foo function define
    
{'secure': 1, 'private': 1}
'''
=================================================================

猜你喜欢

转载自blog.csdn.net/tcy23456/article/details/84072149