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

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

      @lru_cache
      def check(param1, param2, ...) # 检查用户设备类型,版本号等等
          ...
      
  • 相关阅读:
    k8s之pod与Pod控制器
    使用kubeadm部署k8s
    lamp架构
    数据库安装和基本操作
    mysql基础
    Helm Chart 一键部署 Jenkins
    使用 Helm Chart 部署及卸载 istio
    使用 chart 部署 skywalking
    豆瓣电影TOP250和书籍TOP250爬虫
    如何使用 Skywalking Agent ?
  • 原文地址:https://www.cnblogs.com/hiyang/p/12634734.html
Copyright © 2011-2022 走看看