kagxin / blog

个人博客:技术、随笔、生活
https://github.com/kagxin/blog/issues
7 stars 0 forks source link

装饰器 #15

Open kagxin opened 5 years ago

kagxin commented 5 years ago

第一类装饰器

仅仅是一个高阶函数,没有构成闭包,无法对被装饰函数调用时的上下文进行处理。

from functools import wraps

methods = []

def register(func):     # 高阶函数
    methods.append(func)
    return func

@register
def foo():
    print('hello foo')

@register
def bar():
    print('hello bar')

if __name__ == '__main__':
    for func in methods:
        print(func.__name__, func)
"""
0.48802781105041504
"""

第二类装饰器

是一个高阶函数,可以是一个闭包,可以修改对被装饰函数调用时的上下文进行处理。

from functools import wraps
import time

def locked(func):     # 高级函数
    @wraps(func)      # 修正func的元数据
    def dec(*args, **kwargs):
        t0 = time.time()
        res = func(*args, **kwargs)
        x = time.time()-t0   # 计算时差
        print(x)
        return res
    return dec        # return 修改过上下文的dec

def f(n):
    if n < 2:
        return n
    return f(n-1)+f(n-2)

@locked
def foo(n):
    return f(n)

if __name__ == '__main__':
    foo(30)

第三类装饰器

from functools import wraps
import time

def clock(count=True):    
    def dec(func):     # 高级函数
        counter = 0
        @wraps(func)      # 修正func的元数据
        def clocked(*args, **kwargs):
            nonlocal counter
            if count:
                counter += 1
            t0 = time.time()
            res = func(*args, **kwargs)
            x = time.time()-t0   # 计算时差
            print('time:%f'%x, 'times:%d'%counter)
            return res
        return clocked        
    return dec

def f(n):
    if n < 2:
        return n
    return f(n-1)+f(n-2)

@clock(count=True)
def foo(n):
    return f(n)

if __name__ == '__main__':
    foo(30)
    foo(3)
    print(foo.__name__)

"""
time:0.470027 times:1
time:0.000000 times:2
foo
"""
kagxin commented 5 years ago

类装饰器

使用类来实现装饰器,本质上讲装饰器就是一个可调用对象,被装饰的函数作为装饰器的参数,用类实现装饰器。

from functools import wraps
import time

methods = []

class Register(object):

    def __init__(self, func): # 导入时,执行初始化函数
        wraps(func)(self)
        methods.append(func)

    def __call__(self, *args, **kwargs):  # 被装饰函数调用时 相当于值执行__call__
        return self.__wrapped__(*args, **kwargs)  # self.__wrapped__ 就是 func
   # def __get__(self, instance, cls):pass # 未对描述符进行修正,不能作为类中方法的装饰器

@Register
def foo():
    print('hello foo')

@Register
def bar():
    print('hello bar')

if __name__ == '__main__':
    foo()
    bar()
    for func in methods:
        print(func.__name__, func)
kagxin commented 5 years ago

用类的示例作为装饰题(推荐,不要用类作为装饰器,用类作为装饰器,当被装饰的函数为类方法的时候需要对描述符进行修正)