装饰器

装饰器的使用方法

  1. 先定义一个装饰器
  2. 再定义你的业务函数或者类
  3. 最后把装饰器扣在这个函数头上
# 定义装饰器
def decorator(func):
      def wrapper(*args, **kw):
            return func()
      return wrapper

# 定义业务函数并进行装饰
@decorator
def function():
      print("hello, decorator")

普通装饰器

  • 在函数执行前,先记录一行日志
  • 在函数执行完,再记录一行日志
def logger(func):
      def wrapper(*args, **kw):
            print('我准备开始执行了:{} 函数了:'.format(func.__name__))
            
            # 真正执行的是这行。
            func(*args, **kw)

            print('我执行完啦。')
      return wrapper
# 业务函数,计算两个数之和
@logger
def add(x, y):
      print('{} + {} = {}'.format(x, y, x+y))

add(200, 50)

# 执行结果
我准备开始执行了: add 函数了:
200 + 50 = 250
我执行完啦

带参数的函数装饰器

def say_hello(country):
      def wrapper(func):
            def deco(*args, **kwargs):
                  if country == "china":
                        print("你好!")
                  elif country == "america"
                        print("hello.")
                  else:
                        return

                  # 真正执行函数的地方
                  func(*args, **kwargs)
            return deco
      return wrapper

# 小明,中国人
@say_hello("china")
def xiaoming()
      pass

# jack,美国人
@say_hello("america")
def jack()
      pass

xiaoming()
print("------------")
jack()

# 执行结果
你好!
------------
hello.

不带参数的类装饰器

基于类装饰器的实现,必须实现__call____init__两个内置函数
__init__:接收被装饰函数
__call__:实现装饰逻辑

class logger(object):
      def __init__(self, func):
            self.func = func
      
      def __call__(self, *args, **kwargs):
            print("[INFO]:the function {func}() is running...".format(func=self.func__name__))
            return self.func(*args, **kwargs)

@logger
def say(something):
      print("say {}!".format(something))

say("hello")

# 执行结果
[INFO]:the function say() is running...
say hello!

带参数的类装饰器

不带参数的,只能打印INFO级别的日志,正常情况下,我们还需要打印DEBUG WARNING等级别的日志
__init__:不再接收被装饰函数,而是接收传入参数
__call__:接收被装饰函数,实现装饰逻辑

class logger(object):
      def __init__(self, level='INFO'):
            self.level = level

      def __call__(self, func): # 接受函数
            def wrapper(*args, **kwargs):
                  print("[{level}]:the function {func}() is running...".format(level=self.level, func=func.__name__))
                  func(*args, **kwargs)
            return wrapper # 返回函数

@logger(level='WARNING')
def say(something):
      print("say {}!".format(something))

say("hello")

# 执行结果
[WARNING]: the function say() is running...
say hello

使用偏函数与类实现装饰器

绝大多数装饰器都是基于函数和闭包实现de,但这并非制造装饰器的唯一方式.
Python对某个对象是否能通过装饰器(@decorator)形式使用只有一个要求:decorator必须是一个"可被调用(callable)的对象".
对于callable对象,最熟悉的就是函数.除函数外,类也可以是callable对象,只要实现了__call__函数。
还有偏函数也是callable对象
DelayFunc是一个实现了__call__的类,delay返回一个偏函数,在这里delay就可以做为一个装饰器.

import time
import functools


class DelayFunc:
    def __init__(self, duration, func):
        self.duration = duration
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'Wait for {self.duration} seconds...')
        time.sleep(self.duration)
        return self.func(*args, **kwargs)

    def eager_call(self, *args, **kwargs):
        print('Call without delay')
        return self.func(*args, **kwargs)


def delay(duration):
    """
    装饰器:推迟某个执行函数的执行.
    同时提供 .eager_call 方法立即执行
    """
    # 为了避免定义额外函数,
    # 直接使用 functools.partial 帮助构造DelayFunc 实例
    return functools.partial(DelayFunc, duration)


@delay(duration=2)
def add(a, b):
    return a + b

print(add)

print(add(2, 4))

print(add.func)

# 执行结果
# add变成了Delay的实例
# <__main__.DelayFunc object at 0x7f744fd58470>
# 直接调用实例,进入__call__
# Wait for 2 seconds...
# 6
# 实现实例方法
# <function add at 0x7f744fd42d08>
Live what we love, do what we do, follow the heart, and do not hesitate.
原文地址:https://www.cnblogs.com/failan/p/14164534.html