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
    通常使用缓存装饰器,来包裹这些检查函数,避免其被反复调用,进而提高程序运行效率,比如写成下面这样

    --------------------------------------------------------- 恐惧是因为努力的还不够,加油 ~~---------------------------------------------
  • 相关阅读:
    字符串转换相关
    Xcode新功能
    CocoaPods使用详情及版本未更新安装报错
    Cannot create __weak reference in file using manual refs Xcode 7.3
    UIButton实现左文字右图片
    iOS App 上架流程-版本更新注意事项
    iOS App 上架流程-新版本1.0上架
    NSNotification的用法
    NScfBool转bool类型
    百度地图 移动坐标显示该坐标周围对应的信息
  • 原文地址:https://www.cnblogs.com/zhaobowen/p/13550839.html
Copyright © 2011-2022 走看看