[Python]装饰器

简介: [Python]装饰器

image.png


前言

系列文章目录

[Python]目录

视频及资料和课件

链接:https://pan.baidu.com/s/1LCv_qyWslwB-MYw56fjbDg?pwd=1234

提取码:1234

1. 装饰器的定义

装饰器就是给已有函数增加额外功能函数,它本质上就是一个闭包函数

装饰器是一个闭包函数,也就是说装饰器是一个函数嵌套。

1.1 装饰器的功能特点

  1. 不修改已有函数的源代码
  2. 不修改已有函数的调用方式
  3. 给已有函数增加额外的功能

2. 装饰器的示例代码

需要实现一个功能:

在发表评论之前,添加一个"已进行登录验证"

# 需要实现一个功能:
# 在发表评论之前,添加一个"已进行登录验证"
# 定义装饰器
# 如果闭包函数的参数有且只有一个并且是函数类型,那么这个闭包函数称为装饰器
def decorator(func):
    def inner():
        # 在内部函数里面对已有的函数进行装饰
        print('已进行登录验证...')
        func()
    # 返回内部函数
    return inner
# 先定义一个函数
def comment():
    print('发表评论...')
# 调用装饰器对已有函数进行装饰, comment = inner
comment = decorator(comment)
# 调用定义的函数
comment()

代码说明:

闭包函数有且只有一个参数,并且该参数是函数类型,这样定义的函数才是装饰器

写代码要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展。

装饰器相当于原来的函数由闭包的外部函数进行保存,因为闭包内使用了外部函数的变量,且闭包函数没有进行释放,所以外部函数的变量无法进行释放,然后将原来声明的函数进行指向的改变,原来声明的函数指向返回的闭包。

使用装饰器对函数进行功能的拓展,其实是改变函数的指向,由闭包去调用原函数。

3. 装饰器的语法糖写法

如果有多个函数都需要添加登录验证的功能,每次都需要编写comment = decorator(comment)这样代码对已有函数进行装饰,这种做法还是比较麻烦。

Python给提供了一个装饰函数更加简单的写法,那就是语法糖。

语法糖的书写格式是:

@装饰器名

通过语法糖的方式也可以完成对已有函数的装饰.

# 需要实现一个功能:
# 在发表评论之前,添加一个"已进行登录验证"
# 定义装饰器
# 如果闭包函数的参数有且只有一个并且是函数类型,那么这个闭包函数称为装饰器
def decorator(func):
    def inner():
        # 在内部函数里面对已有的函数进行装饰
        print('已进行登录验证...')
        func()
    # 返回内部函数
    return inner
# 先定义一个函数
# 使用语法糖的方法对 comment 函数进行装饰
# 此代码相当于 comment = decorator(comment)
# 对函数进行装饰后,comment = inner
@decorator
def comment():
    print('发表评论...')
# 调用定义的函数
comment()

4. 装饰器的执行时机

装饰器的执行时机:

当当前模块加载完成后,装饰器会立即执行,对已有的函数进行装饰。

# 需要实现一个功能:
# 在发表评论之前,添加一个"已进行登录验证"
# 定义装饰器
# 如果闭包函数的参数有且只有一个并且是函数类型,那么这个闭包函数称为装饰器
def decorator(func):
    print('装饰器执行了...')
    def inner():
        # 在内部函数里面对已有的函数进行装饰
        print('已进行登录验证...')
        func()
    # 返回内部函数
    return inner
# 先定义一个函数
# 使用语法糖的方法对 comment 函数进行装饰
# 此代码相当于 comment = decorator(comment)
# 对函数进行装饰后,comment = inner
@decorator
def comment():
    print('发表评论...')
# 调用定义的函数
# comment()

导入装饰器的模块

import pycode

上述代码说明:当当前模块加载完成后,装饰器会立即执行,对已有的函数进行装饰。

5. 装饰器的使用

5.1 装饰器的使用场景

  1. 对函数的功能进行拓展
  2. 函数执行时间的统计
  3. 输出日志信息

5.2 装饰器实现已有函数执行时间的统计

import time
# 定义装饰器
def decorator(func):
    def inner():
        # 获取函数执行开始的时间
        begin = time.time()
        # 调用执行函数
        func()
        # 获取函数执行结束的时间
        end = time.time()
        # 打印函数的执行时间
        print('函数执行完成,用时:', end-begin)
    # 返回内部函数
    return inner
# 定义函数,并对其进行装饰
# work = decorator(work)
@decorator
def work():
    sum = 0
    for i in range(10000):
        sum += i
    print(sum)
# 调用执行函数
work()

6. 通用装饰器的使用

通用装饰器,即这个装饰器可以装饰任意的函数

6.1 装饰带有参数的函数

使用装饰器装饰带有参数的函数时,装饰器的内部函数的类型需要和要进行装饰的已有函数的类型保持一致,即内部函数需要的参数个数要和需要进行装饰的函数一致。

# 定义装饰器
def decorator(func):
    # 由于内部函数内执行的函数需要两个参数,所以这里需要接收两个参数
    # 内部函数的类型要和需要进行装饰的已有的函数的类型一致
    def inner(num1, num2):
        # 在内部函数对已有函数进行装饰
        print('正在执行函数...')
        func(num1, num2)
    return inner
# 进行装饰
@decorator
def add(num1, num2):
    print('相加结果为:', num1+num2)
add(1, 2)

6.2 装饰带有参数和返回值的函数

使用装饰器装饰函数时,装饰器的内部函数的类型需要和要进行装饰的已有函数的类型保持一致。

装饰带有返回值的函数,装饰器的内部函数需要接收调用函数的返回值,与此同时并向外返回接收到的返回值。

# 定义装饰器
def decorator(func):
    # 由于内部函数内执行的函数需要两个参数,所以这里需要接收两个参数
    # 内部函数的类型要和需要进行装饰的已有的函数的类型一致
    def inner(num1, num2):
        # 在内部函数对已有函数进行装饰
        print('正在执行函数...')
        res = func(num1, num2)
        return res
    return inner
# 进行装饰
@decorator
def add(num1, num2):
    # print('相加结果为:', num1+num2)
    return num1 + num2
res = add(1, 2)
print('相加的结果为:', res)

6.3 装饰带有不定长参数和返回值的函数

  • *args:接收参数后,为元组类型
  • **kwargs:接收参数后,为字典类型

该装饰器就是通用装饰器。

# 定义装饰器
def decorator(func):
    # 由于内部函数调用的函数接收的不定长
    # 所以此处接收的参数也为不定长
    def inner(*args, **kwargs):
        # 在内部函数对已有函数进行装饰
        print('正在执行函数...')
        # 注意,在次数传参时,不能直接将 args, kwargs 直接传入
        # 直接传入 args, kwargs 会被作为两个单独的参数,一个元组类型,一个字典类型
        # 所以这里需要先进行拆包
        # 这里对元组和字典进行拆包,仅限于结合不定长参数的函数使用
        res = func(*args, **kwargs)
        return res
    return inner
# 该函数接收不定长参数,不定长关键字参数
# 进行装饰
@decorator
def add(*args, **kwargs):
    sum = 0
    # 循环遍历 args,看是否有不定长参数传入函数
    for val in args:
        sum += val
    # 循环遍历 kwargs,看是否有不定长关键字参数传入函数
    # 由于次数不需要 键 ,所以只遍历 值
    for val in kwargs.values():
        sum += val
    return sum
res = add(1, 2)
print('相加的结果为:', res)

装饰什么样的函数,内部函数就什么样。

6.4 通用装饰器

# 定义装饰器
def decorator(func):
    # 由于内部函数调用的函数接收的不定长
    # 所以此处接收的参数也为不定长
    def inner(*args, **kwargs):
        # 在内部函数对已有函数进行装饰
        print('正在执行函数...')
        # 注意,在次数传参时,不能直接将 args, kwargs 直接传入
        # 直接传入 args, kwargs 会被作为两个单独的参数,一个元组类型,一个字典类型
        # 所以这里需要先进行拆包
        # 这里对元组和字典进行拆包,仅限于结合不定长参数的函数使用
        res = func(*args, **kwargs)
        # 进行装饰的函数没有返回值,这里接受和返回都为 None
        return res
    return inner
@decorator
def f1():
    print('测试通用装饰器')
@decorator
def f2(num):
    return num
f1()
res = f2(2)
print(res)

7. 多个装饰器的使用

使用多个装饰器装饰一个函数。

需要实现的功能:

在原函数输出一句话的基础上,在该句话前后加上

,在此基础上,再在前后加上

# 装饰器 1
def make_div(func):
    print('make_div执行了...')
    def inner():
        # 对内部函数进行装饰
        res = '<div>' + func() + '</div>'
        return res
    return inner
# 装饰器 2
def make_p(func):
    print('make_p执行了...')
    def inner():
        # 对内部函数进行装饰
        res = '<p>' + func() + '</p>'
        return res
    return inner
# 装饰执行过程:make_div( make_p( content ) )
@make_div
@make_p
def content():
    return '人生苦短,我用Python'
res = content()
print(res)

从执行结果,可以看出,装饰的执行过程是从下向上进行装饰的

8. 带有参数的装饰器

带有参数的装饰器就是使用装饰器装饰函数的时候可以传入指定参数,对不同的函数,传入不同的参数,可以进行不同的装饰。

语法格式:

@装饰器(参数,...

注意:装饰器只能接收一个参数,且这个参数是函数类型

# 创建一个函数,用于创建并返回装饰器
# 该函数接收的参数为 对函数不同的装饰参数
def make_decorator(dec):
    # 定义装饰器
    def decorator(func):
        def inner(a, b):
            # 对函数进行装饰
            print(dec)
            res = func(a, b)
            return res
        return inner
    # 返回创建的装饰器
    return decorator
# 定义函数,并对该函数进行装饰
# 装饰函数的过程:
# 1. 先执行函数 make_decorator() 得到装饰器 decorator
# 2. 使用得到的装饰器 decorator 装饰函数 decorator(add_num) 返回装饰后的函数
@make_decorator('正在进行加法计算...')
def add_num(a, b):
    return a + b
# 调用函数
res = add_num(1, 2)
print('计算结果为: ', res)

9. 类装饰器的使用

使用类来装饰函数

使用类装饰器装饰函数,需要实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。

# 定义类装饰器
class MyDecorator(object):
    # 当使用类装饰器装饰函数,默认会调用 __init__ 方法
    # 使用 __init__ 初始化对象
    def __init__(self, func):
        # 由于对函数进行装饰后,装饰前的函数不希望再次被调用
        # 所以原函数设置为私有属性
        self.__func = func
    # 实现`__call__`方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。
    def __call__(self, *args, **kwargs):
        # 装饰函数
        print('课讲完了')
        self.__func()
# 使用类装饰器,此处相当于
# show = MyDecorator(show)
# 所以装饰以后为一个对象,对象能够调用需要实现 __call__ 方法
@MyDecorator
def show():
    print('下课了...')
show()

拓展:函数之所以能够调用,是因为函数内部实现了 __call__ 方法。

def test():
    print('test()')
print(dir(test))



相关文章
|
27天前
|
Python
深入理解Python装饰器:从入门到实践####
本文旨在通过简明扼要的方式,为读者揭开Python装饰器的神秘面纱,从基本概念、工作原理到实际应用场景进行全面解析。不同于常规的摘要仅概述内容概要,本文将直接以一段精炼代码示例开篇,展示装饰器如何优雅地增强函数功能,激发读者探索兴趣,随后深入探讨其背后的机制与高级用法。 ####
51 11
|
23天前
|
设计模式 缓存 开发者
深入浅出Python装饰器
【10月更文挑战第39天】本文将通过浅显易懂的语言和生动的比喻,带你探索Python中一个神奇而又强大的特性——装饰器。我们将一起揭开装饰器的神秘面纱,了解它的工作原理,并通过实际代码示例学习如何应用它来美化我们的代码。无论你是编程新手还是有经验的开发者,这篇文章都将为你打开一扇新的大门,让你的代码更加优雅和高效。
|
23天前
|
缓存 测试技术 数据库
深入理解Python中的装饰器
在本文中,我们将探讨Python语言中一个强大而灵活的特性——装饰器。装饰器允许开发者在不修改原有函数或方法代码的情况下增加额外的功能,这大大提高了代码的复用性和可读性。通过具体示例和应用场景的讲解,本篇文章旨在为读者提供一个关于如何使用装饰器的全面指南,包括装饰器的定义、使用场景、以及如何自定义装饰器等内容。
|
28天前
|
设计模式 Python
掌握Python中的装饰器
【10月更文挑战第34天】装饰器是Python中一种强大的工具,它允许我们在不修改原函数代码的情况下增加其功能。本文通过简单易懂的语言和实例,引导你理解装饰器的概念、种类及其应用,帮助你在编程实践中灵活使用这一高级特性。
|
5天前
|
存储 缓存 Python
Python中的装饰器深度解析与实践
在Python的世界里,装饰器如同一位神秘的魔法师,它拥有改变函数行为的能力。本文将揭开装饰器的神秘面纱,通过直观的代码示例,引导你理解其工作原理,并掌握如何在实际项目中灵活运用这一强大的工具。从基础到进阶,我们将一起探索装饰器的魅力所在。
|
18天前
|
开发框架 缓存 测试技术
Python中的装饰器:魔法般的功能增强
在Python编程中,装饰器是一种强大而灵活的工具,它允许开发者修改或扩展函数和类的行为。本文将深入探讨Python装饰器的工作原理,并通过实例演示如何创建和使用自定义装饰器来增强代码的功能性和可读性。我们将从基础概念讲起,逐步深入到高级应用,揭示装饰器背后的“魔法”,并展示它们在实际开发中的多种用途。
|
24天前
|
缓存 监控 测试技术
Python中的装饰器:功能扩展与代码复用的利器###
本文深入探讨了Python中装饰器的概念、实现机制及其在实际开发中的应用价值。通过生动的实例和详尽的解释,文章展示了装饰器如何增强函数功能、提升代码可读性和维护性,并鼓励读者在项目中灵活运用这一强大的语言特性。 ###
|
27天前
|
缓存 开发者 Python
探索Python中的装饰器:简化代码,增强功能
【10月更文挑战第35天】装饰器在Python中是一种强大的工具,它允许开发者在不修改原有函数代码的情况下增加额外的功能。本文旨在通过简明的语言和实际的编码示例,带领读者理解装饰器的概念、用法及其在实际编程场景中的应用,从而提升代码的可读性和复用性。
|
23天前
|
设计模式 缓存 开发框架
Python中的装饰器:从入门到实践####
本文深入探讨了Python中装饰器的工作原理与应用,通过具体案例展示了如何利用装饰器增强函数功能、提高代码复用性和可读性。读者将学习到装饰器的基本概念、实现方法及其在实际项目开发中的实用技巧。 ####
26 3
|
28天前
|
设计模式 缓存 监控
Python中的装饰器:代码的魔法增强剂
在Python编程中,装饰器是一种强大而灵活的工具,它允许程序员在不修改函数或方法源代码的情况下增加额外的功能。本文将探讨装饰器的定义、工作原理以及如何通过自定义和标准库中的装饰器来优化代码结构和提高开发效率。通过实例演示,我们将深入了解装饰器的应用,包括日志记录、性能测量、事务处理等常见场景。此外,我们还将讨论装饰器的高级用法,如带参数的装饰器和类装饰器,为读者提供全面的装饰器使用指南。