• 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

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

      @lru_cache
      def check(param1, param2, ...) # 检查用户设备类型,版本号等等
          ...
      
  • 相关阅读:
    linux2.6.24.3下移植SD/MMC到S3C2440上的全历程
    设置装备布置了下双表示器
    Virtual Box 1.5.0 - 实用的“无缝窗口”
    oracle DB LINK 运用
    Linux下的tidy安置
    Linux效劳器装机安全疾速进阶指南(2)
    Linux下历程间通信
    Firefox 3 CSS Hack
    Linux下的搜刮东西find根基用法
    Linux效能器装机平安快速进阶指南(3)
  • 原文地址:https://www.cnblogs.com/hiyang/p/12634734.html
Copyright © 2020-2023  润新知