ython快速入门学习笔记(进阶篇)二十:装饰器

  • 原创
  • 作者:程序员三丰
  • 发布时间:2026-04-05 12:36
  • 浏览量:8
python入门第二十课,主要是学习了装饰器,装饰器是一种在不改变原函数代码的前提下,动态增加函数功能的高级语法糖,提升了代码的复用性与可读性。

什么是装饰器

装饰器是一种在『不修改原函数代码』的前提下,对函数进行『增强』的工具。它是Python中非常强大的语法特性,常用于:日志、校验、计时、缓存、权限控制等。

核心语法:装饰器是一种可调用对象(通常是函数),接收一个函数作为参数,并返回一个函数。

通常分为两个类型:函数装饰器、类装饰器。下面详细介绍。

函数装饰器

需求:在不修改add函数的前提下,给add函数增加一些额外的功能,例如:计算前打印一句欢迎语。

1️⃣定义函数装饰器

def say_hello(func):
    def wrapper(*args, **kwargs):
        print("你好,我要开始计算了")
        return func(*args, **kwargs)
    return wrapper

定义装饰器核心规则:

  • 接收被装饰的函数、同时返回新函数(wrapper)。
  • 装饰器“吐出来”的是 wrapper 函数,以后别人调用的也是 wrapper 函数。
  • 为了保证参数的兼容性,wrapper 函数通过 args 和 kwargs 接收参数。
  • wrapper 函数中主要做的是:调用原函数(被装饰的函数)、执行其它逻辑,但记得将原函数的返回值 return 出去。

2️⃣使用函数装饰器(手动装饰)

def add(a, b, c):
    res = a + b + c
    print(f'{a}和{b}和{c}相加的结果是:{res}')
    return res

# 调用 say_hello 装饰器,对 add 函数进行装饰,并得到装饰后的新函数
add = say_hello(add)
result = add(1, 2, 3)
print(result)

上述代码运行结果:

你好,我要开始计算了
1和2和3相加的结果是:6
6

3️⃣使用函数装饰器(语法糖@)

@say_hello
def add(a, b, c):
    res = a + b + c
    print(f'{a}和{b}和{c}相加的结果是:{res}')
    return res

result = add(1, 2, 3)
print(result)

上述代码运行结果:

你好,我要开始计算了
1和2和3相加的结果是:6
6

上述代码的执行流程:

@say_hello会自动执行:add = say_hello(add)

➁ 以后调用add()时,真正执行的是wrapper()

4️⃣带参数的函数装饰器(三层嵌套)

需求:装饰不同的函数,打印不同的欢迎语。

核心:带参数的装饰器最终是三层嵌套:外层接收配置、中间层接收函数、内层接收具体参数。

def calculate(msg):
    def outer(func):
        def wrapper(*args, **kwargs):
            print(f'你好,我要开始{msg}计算了')
            return func(*args, **kwargs)
        return wrapper
    return outer

# 装饰加法函数
@calculate('加法')
def add(a, b, c):
    res = a + b + c
    print(f'{a}和{b}和{c}相加的结果是:{res}')
    return res

# 装饰减法函数
@calculate('减法')
def sub(a, b):
    res = a - b
    print(f'{a}和{b}相减的结果是:{res}')
    return res

result = add(1, 2, 3)
print(result)

print()

result1 = sub(4, 5)
print(result1)

上述代码运行结果如下:

你好,我要开始加法计算了
1和2和3相加的结果是:6
6

你好,我要开始减法计算了
4和5相减的结果是:-1
-1

5️⃣多个函数装饰器一起使用

核心:注意装饰顺序,距离函数最近的装饰器,会先工作。

例如下面的代码:test2先装饰,test1再装饰。

def decorator1(func):
    print('我是decorator1装饰器')
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print('decorator1追加的逻辑')
        return res
    return wrapper

def decorator2(func):
    print('我是decorator2装饰器')
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print('decorator2追加的逻辑')
        return res
    return wrapper

@decorator1
@decorator2
def add(a, b, c):
    res = a + b + c
    print(f'{a}和{b}和{c}相加的结果是:{res}')
    return res

result = add(1, 3, 4)
print(result)

上述代码运行结果如下:

我是decorator2装饰器
我是decorator1装饰器
1和3和4相加的结果是:8
decorator2追加的逻辑
decorator1追加的逻辑
8

类装饰器

包含__call__方法的类,就是类装饰器。

像调用函数一样,去调用类装饰器的实例对象,就会触发__call__方法的调用。

__call__方法通常接收一个函数作为参数,并且会返回一个新函数。

1️⃣定义类装饰器

需求和之前一样,还是给add函数增加【打印欢迎语】的功能。

class SayHello:
    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print('你好,我要开始计算了')
            return func(*args, **kwargs)
        return wrapper

2️⃣使用类装饰器(手动装饰)

手动使用类装饰器的流程:先创建类的实例对象,随后调用实例对象,并传入要装饰的函数。

# 定义被装饰函数
def add(x, y):
    res = x + y
    print(f'{x}和{y}相加的结果是{res}')
    return res

# 使用 SayHello 去装饰 add 函数(手动装饰)
say_hello_inst = SayHello()
add_decorator = say_hello_inst(add)

# 调用装饰后的函数
result = add_decorator(10, 20)
print(result)

# 运行结果如下:
# 你好,我要开始计算了
# 10和20相加的结果是30
# 30

3️⃣使用类装饰器(语法糖@)

注意通过<font style="color:#DF2A3F;">语法糖@</font>使用装饰器时,类名后要加圆括号调用

@SayHello()
def add(x, y):
    res = x + y
    print(f'{x}和{y}相加的结果是{res}')
    return res

# 直接调用被装饰的函数 add,但调用的是被装饰后的新函数
result = add(1, 2)
print(result)

# 运行结果如下:
# 你好,我要开始计算了
# 1和2相加的结果是3
# 3

4️⃣带参数的类装饰器(三层嵌套)

带参数的类装饰器写起来,要比带参数的函数装饰器简单,不需要三层结构。

class SayHello:
    def __init__(self, msg):
        self.msg = msg

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f'你好,我要开始{self.msg}计算了')
            return func(*args, **kwargs)
        return wrapper

@SayHello('加法')
def add(x, y):
    res = x + y
    print(f'{x}和{y}相加的结果是{res}')
    return res

# 直接调用被装饰的函数 add,但调用的是被装饰后的新函数
result = add(1, 2)
print(result)

# 运行结果如下:
# 你好,我要开始加法计算了
# 1和2相加的结果是3
# 3

5️⃣多个类装饰器一起使用

class SayHello:
    def __init__(self, msg):
        self.msg = msg

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f'你好,我要开始{self.msg}计算了')
            return func(*args, **kwargs)
        return wrapper

class Helper:
    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print('相信我,绝对可以的')
            return func(*args, **kwargs)
        return wrapper

@SayHello('加法')
@Helper()
def add(x, y):
    res = x + y
    print(f'{x}和{y}相加的结果是{res}')
    return res

# 直接调用被装饰的函数 add,但调用的是被装饰后的新函数
result = add(1, 2)
print(result)
声明:本文为原创文章,51blog.xyz和作者拥有版权,如需转载,请注明来源于51blog.xyz并保留原文链接:https://mp.51blog.xyz/article/122.html

文章归档

推荐文章

buildadmin logo
Thinkphp8 Vue3 Element PLus TypeScript Vite Pinia

🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。

热门标签

PHP ThinkPHP ThinkPHP5.1 Go Mysql Mysql5.7 Redis Linux CentOS7 Git HTML CSS CSS3 Javascript JQuery Vue LayUI VMware Uniapp 微信小程序 docker wiki Confluence7 学习笔记 uView ES6 Ant Design Pro of Vue React ThinkPHP6.0 chrome 扩展 翻译工具 Nuxt SSR 服务端渲染 scrollreveal.js ThinkPHP8.0 Mac webman 跨域CORS vscode GitHub ECharts Canvas vue3 three.js 微信支付 PHP全栈开发 Python AI 人工智能 AI生成 工作经验 实战笔记