Python从进阶到高级—通俗易懂版(四)

# ==================================
# Author : Mikigo
# Env    :deepin 20.4 os
# ==================================

1、装饰器

装饰器就是使用 @ 符号,像帽子一样扣在函数的头上,是 Python 中的一种语法糖。

前面讲类方法和静态方法的时候提到过,使用方法非常简单。

原理实际上就是将它所装饰的函数作为参数,最后返回这个函数。

@classmethod
def mikigo():
    print("My name is mikigo")

这样的写法等同于

def mikigo():
    print("My name is mikigo")
    
mikigo = classmethod(mikigo)

对比一下,使用装饰器可读性很高,很优雅是吧,语法糖就是给你点糖吃,让你上瘾。

定义一个装饰器

  • 不带参数的装饰器

举个例子:

def logger(func):
    def wrapper(*args, **kw):
        print('我要开始搞 {} 函数了'.format(func.__name__))
        func(*args, **kw)  # 函数执行
        print('搞完了')
    return wrapper

这是一个简单的装饰函数,用途就是在函数执行前后分别打印点日志。

有2点需要注意:

(1)装机器是一种高阶函数,在函数内层定义函数,并返回内层函数对象,多层级同理。

(2)最外层函数传入的参数是被装饰函数的函数对象。

@logger
def add(x, y):
    print('{} + {} = {}'.format(x, y, x+y))

来,试试看

add(5, 10)
我要开始搞 add 函数了
5 + 10 = 15
搞完了
  • 带参数的装饰器
from functools import wraps

def logger(say_some):
    @wraps
    def wrapper(func):
        def deco(*args, **kw):
            print("搞之前我先说两句:{}".format(say_some))
            print('我要开始搞 {} 函数了:'.format(func.__name__))
            func(*args, **kw)  # 函数执行
            print('搞完了')
        return deco
    return wrapper

你看,都是外层函数返回内层函数对象,参数放在最外层。@wraps 可加可不加,它的用途主要是保留被装饰函数的一些属性值。

@logger("别整,不得劲儿~")
def add(x, y):
    print('{} + {} = {}'.format(x, y, x+y))

执行试试

add(5, 10)
搞之前我先说两句:别整,不得劲儿~
我要开始搞 add 函数了:
5 + 10 = 15
搞完了

很奈斯,就这点儿东西。

这是最常见的实现方法,现在咱们搞点不一样的。

基于类实现装饰器

基于类装饰器的实现,必须实现 __call____init__ 两个魔法函数。

  • 不带参数的类装饰器
class logger:

    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('我要开始搞 {} 函数了'.format(self.func.__name__))
        f = self.func(*args, **kwargs)
        print('搞完了')
        return f

不带参数的类装饰,func 是通过 init 函数里面构造的。

试试看

@logger
def add(x, y):
    print('{} + {} = {}'.format(x, y, x+y))
add(5, 10)
我要开始搞 add 函数了
5 + 10 = 15
搞完了

so easy 哈,鸭子类型,实现了装饰器协议,就是装饰器对象。

  • 带参数的类装饰器
class logger:

    def __init__(self, say_some):
        self.say_some = say_some

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print("搞之前我先说两句:{}".format(self.say_some))
            print('我要开始搞 {} 函数了'.format(func.__name__))
            func(*args, **kwargs)
            print('搞完了')
        return wrapper

带参数的类装饰器,func 是在 call 函数里面,参数是通过 init函数传入的,这里区别比较大哈。

@logger("别整,真的不得劲儿~")
def add(x, y):
    print('{} + {} = {}'.format(x, y, x+y))
add(5, 10)
搞之前我先说两句:别整,真的不得劲儿~
我要开始搞 add 函数了
5 + 10 = 15
搞完了

这类属于装饰器的高阶用法了,在一些优秀的框架源码里面比较常见。

posted @ 2022-10-21 11:38  mikigo  阅读(68)  评论(0编辑  收藏  举报