zoukankan      html  css  js  c++  java
  • python函数装饰器和类装饰器

    函数装饰器

    1、简单装饰器

    def my_decorator(func):
        def wrapper():
            print('wrapper of decorator')
            func()
        return wrapper
    
    def greet():
        print('hello world')
    
    greet = my_decorator(greet)
    greet()
    
    # 输出
    # wrapper of decorator
    # hello world
    

    上述代码在 Python 中有更简单、更优雅的表示:

    def my_decorator(func):
        def wrapper():
            print('wrapper of decorator')
            func()
        return wrapper
    
    @my_decorator
    def greet():
        print('hello world')
    
    greet()
    
    # 输出
    # wrapper of decorator
    # hello world
    

    2、带参数的装饰器

    def my_decorator(func):
        def wrapper(*args, **kwargs):
            print('wrapper of decorator')
            func(*args, **kwargs)
        return wrapper
    
    @my_decorator
    def greet(message):
        print(message)
    
    greet('hello world')
    
    # 输出
    # wrapper of decorator
    # hello world
    

    3、自定义参数的装饰器

    def repeat(num):
        def my_decorator(func):
            def wrapper(*args, **kwargs):
                for i in range(num):
                    print('wrapper of decorator {}'.format(i))
                    func(*args, **kwargs)
            return wrapper
        return my_decorator
    
    @repeat(4)
    def greet(message):
        print(message)
    
    greet('hello world')
    
    # 输出:
    # wrapper of decorator 0
    # hello world
    # wrapper of decorator 1
    # hello world
    # wrapper of decorator 2
    # hello world
    # wrapper of decorator 3
    # hello world
    

    4、原函数还是原函数吗
    试着打印出 greet() 函数的一些元信息:

    greet.__name__
    ## 输出
    'wrapper'
    
    help(greet)
    # 输出
    Help on function wrapper in module __main__:
    
    wrapper(*args, **kwargs)
    

    greet() 函数被装饰以后,它的元信息变了。元信息告诉我们“它不再是以前的那个 greet() 函数,而是被 wrapper() 函数取代了”。

    为了解决这个问题,通常使用内置的装饰器@functools.wrap,它会帮助保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装饰器函数里)。

    import functools
    
    def my_decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('wrapper of decorator')
            func(*args, **kwargs)
        return wrapper
        
    @my_decorator
    def greet(message):
        print(message)
    
    greet.__name__
    
    # 输出
    'greet'
    

    类装饰器

    实际上,类也可以作为装饰器。类装饰器主要依赖于函数__call__(),每当你调用一个类的示例时,函数__call__()就会被执行一次。

    class Count:
        def __init__(self, func):
            self.func = func
            self.num_calls = 0
    
        def __call__(self, *args, **kwargs):
            self.num_calls += 1
            print('num of calls is: {}'.format(self.num_calls))
            return self.func(*args, **kwargs)
    
    @Count
    def example():
        print("hello world")
    
    example()
    
    # 输出
    num of calls is: 1
    hello world
    
    example()
    
    # 输出
    num of calls is: 2
    hello world
    

    我们定义了类 Count,初始化时传入原函数 func(),而__call__()函数表示让变量 num_calls 自增 1,然后打印,并且调用原函数。因此,在我们第一次调用函数 example()时,num_calls 的值是 1,而在第二次调用时,它的值变成了 2

    装饰器的应用

    身份认证 authenticate
    日志记录
    输入合理性检查 validation_check
    缓存 lru_cache
    通常使用缓存装饰器,来包裹这些检查函数,避免其被反复调用,进而提高程序运行效率,比如写成下面这样

    --------------------------------------------------------- 恐惧是因为努力的还不够,加油 ~~---------------------------------------------
  • 相关阅读:
    数据库高级链表查询,重点可以多看看
    数据库多表查询,一对一关系,一对多关系,多对多关系
    Django基础
    前端之JavaScript
    前端之Jquery
    CF888E Maximum Subsequence-折半搜索
    HNOI2010 平面图判定
    CEOI 2011Traffic
    LuoguP1710 地铁涨价
    Luogu2059 卡牌游戏-概率DP
  • 原文地址:https://www.cnblogs.com/zhaobowen/p/13550839.html
Copyright © 2011-2022 走看看