欢迎访问宙启技术站
智能推送

Python装饰器函数详解及实例

发布时间:2023-06-22 05:38:28

Python装饰器是Python语言中一个重要的概念,它是在函数运行时动态地修改函数的行为。Python装饰器允许我们在不修改函数的情况下扩展或修改函数的行为。这篇文章将详细介绍Python装饰器的定义、作用、分类、使用方法、实例等方面的知识。

一、装饰器函数的概念

装饰器函数是Python语法的一个特性。它是用来修改或者包装函数的函数。装饰器函数是高阶函数的一种,它接收一个函数作为参数并返回一个被修改后的函数。这种做法在Python中被广泛应用,特别是在web框架和数据库ORM框架中经常见到。

二、装饰器函数的作用

Python装饰器提供了一种统一且优美的方式,可以在不改变函数本身的情况下扩展或者修改函数的行为。

装饰器函数可以用来增强函数的功能,比如计时,缓存,权限认证,参数校验等。

装饰器函数也可以用来给函数增加一些元信息(比如函数名、文档字符串),这有助于提高代码的可读性和可维护性。

三、装饰器函数的分类

根据装饰器是否需要参数,可以将装饰器分为有参装饰器和无参装饰器。

1. 无参装饰器

无参装饰器是最简单的装饰器。它不需要传递任何参数,只需要在函数定义前使用@符号来调用即可。

例如,下面的代码演示了一个简单的无参装饰器,用来计算函数运行时间:

  import time

  def timeit(func):

      def wrapper(*args, **kwargs):

          start_time = time.time()

          res = func(*args, **kwargs)

          end_time = time.time()

          print(f'函数{func.__name__}的运行时间为{end_time-start_time}秒')

          return res

      return wrapper

  @timeit

  def foo():

      time.sleep(3)

  foo()

输出结果:

  函数foo的运行时间为3.0035061836242676秒

2. 有参装饰器

有参装饰器和无参装饰器的区别就在于有参装饰器需要传递参数。有参装饰器可以用来执行额外的任务,比如设置缓存时间。

例如,下面的代码演示了一个简单的有参装饰器,用来设置函数缓存时间:

  import functools

  def cache(duration):

      def dec(func):

          @functools.wraps(func)

          def wrapper(*args, **kwargs):

              key = str(args) + str(kwargs)

              now_time = time.time()

              if key in wrapper.cache:

                  if now_time - wrapper.cache[key]['time'] > duration:

                      print(f'缓存超时,更新缓存{key}')

                      wrapper.cache.pop(key)

                      res = func(*args, **kwargs)

                      wrapper.cache[key] = {'data': res, 'time': now_time}

                  else:

                      print(f'从缓存中获取{key}')

                      res = wrapper.cache[key]['data']

              else:

                  print(f' 次执行{key},写入缓存')

                  res = func(*args, **kwargs)

                  wrapper.cache[key] = {'data': res, 'time': now_time}

              return res

          wrapper.cache = {}

          return wrapper

      return dec

  @cache(duration=3)

  def bar(a, b):

      time.sleep(2)

      return a + b

  print(bar(1, 2))

  print(bar(1, 2))

输出结果:

   次执行(1, 2){},写入缓存

  3

  从缓存中获取(1, 2){}

  3

四、装饰器函数的使用方法

Python装饰器的使用方法非常简单,只需要在函数定义前添加@装饰器函数名即可。

例如,下面的代码演示了如何使用装饰器函数来扩展函数功能:

  import time

  def timeit(func):

      def wrapper(*args, **kwargs):

          start_time = time.time()

          res = func(*args, **kwargs)

          end_time = time.time()

          print(f'函数{func.__name__}的运行时间为{end_time-start_time}秒')

          return res

      return wrapper

  @timeit

  def foo():

      time.sleep(3)

  foo()

输出结果:

  函数foo的运行时间为3.0035061836242676秒

五、装饰器函数的实例

1. 计时装饰器

下面的代码演示了如何使用装饰器函数来计算函数的运行时间:

  import time

  def timeit(func):

      def wrapper(*args, **kwargs):

          start_time = time.time()

          res = func(*args, **kwargs)

          end_time = time.time()

          print(f'函数{func.__name__}的运行时间为{end_time-start_time}秒')

          return res

      return wrapper

  @timeit

  def foo():

      time.sleep(3)

  foo()

输出结果:

  函数foo的运行时间为3.0035061836242676秒

2. 缓存装饰器

下面的代码演示了如何使用装饰器函数来缓存函数的运算结果:

  import functools

  def cache(func):

      @functools.wraps(func)

      def wrapper(*args, **kwargs):

          key = str(args) + str(kwargs)

          if key in wrapper.cache:

              print(f'从缓存中获取{key}')

              return wrapper.cache[key]

          else:

              print(f' 次执行{key},写入缓存')

              res = func(*args, **kwargs)

              wrapper.cache[key] = res

              return res

      wrapper.cache = {}

      return wrapper

  @cache

  def bar(a, b):

      time.sleep(3)

      return a + b

  print(bar(1, 2))

  print(bar(1, 2))

输出结果:

   次执行(1, 2){},写入缓存

  3

  从缓存中获取(1, 2){}

  3

3. 权限认证装饰器

下面的代码演示了如何使用装饰器函数来进行权限认证:

  def login_required(func):

      def wrapper(request, *args, **kwargs):

          if request.get('user'):

              return func(request, *args, **kwargs)

          else:

              return '请先登录'

      return wrapper

  @login_required

  def user_page(request):

      return f'欢迎您,{request.get("user")}'

  print(user_page({'user': 'Tom'}))

  print(user_page({'admin': 'Tom'}))

输出结果:

  欢迎您,Tom

  请先登录

4. 参数校验装饰器

下面的代码演示了如何使用装饰器函数来进行参数校验:

  def check_args(func):

      def wrapper(*args, **kwargs):

          if not all(isinstance(arg, int) for arg in args):

              return '参数类型错误'

          if 'page' in kwargs and not isinstance(kwargs['page'], int):

              return 'page参数类型错误'

          return func(*args, **kwargs)

      return wrapper

  @check_args

  def get_data(a, b, page=None):

      return [i for i in range(a, b+1)][page*10-10:page*10] if page else [i for i in range(a, b+1)]

  print(get_data(2, 100))

  print(get_data('a', 'b'))

  print(get_data(2, 100, page=1))

  print(get_data(2, 100, page='a'))

输出结果:

  [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

  参数类型错误

  [