python的装饰器

python的装饰器

1、装饰器的定义

已有的函数添加额外功能的函数,它本质上就是一个闭包函数

装饰器的功能特点:

  1. 不修改已有函数的功能特点
  2. 不修改已有函数的调用方式
  3. 给已有函数添加额外的功能

需求:给comment函数添加一个额外功能(需要先登陆,再评论)

要求:不能改变现有comment函数,不能修改comment函数的调用方式,还要添加一个额外功能

答:可以使用装饰器实现,装饰器的本质是一个闭包函数 =》① 有嵌套 ② 有引用 ③ 有返回

# 装饰器都有一个参数fn,代表要装饰函数的名称
def loggin(fn):
    def inner():
        # 在引用fn函数之前,添加额外功能
        print('请先登陆!')

        # 引用局部变量
        fn()

    return inner


@loggin
def comment():
    print('发表评论:')


comment()

2、案例之给程序额外添加一个计算时间的功能

import time


def get_time(fn):
    # 定义一个内部函数
    def inner():
        star = time.time()
        # 有引用
        fn()
        end = time.time()
        print(f'此程序执行了{(end - star):.02f}秒!')

    # 返回内部函数的地址
    return inner


@get_time  # 在使用装饰器的时候自动将函数地址传给装饰器
def demo():
    list1 = []
    for i in range(10000000):
        list1.append(i)


demo()

3、装饰器的执行原理

image-20231003170154399

def logging(fn):
    # fn = comment
    def inner():
        # 在引用fn函数之前,添加额外功能
        print('请先登陆!')

        # 引用局部变量
        fn()

    return inner


@logging  # 这里相当于将comment的地址作为参数传给了logging
def comment():
    print('发表评论:')


comment()   # 并不是执行comment函数,而是执行logging函数的返回结果,inner函数

以下代码效果等同

def logging(fn):
    def inner():
        print('请先登陆!')
        fn()

    return inner


def comment():
    print('发表评论')

# 等同于@logging 的效果
comment = logging(comment)  # 为了满足装饰器的不能修改调用的方式的需求,这里使用同名变量
comment()  # 这里调用的是inner函数,而不是comment函数,全局变量的优先级更大

4、装饰器修饰带有参数的函数

def message(fn):
    # fn = sum_num
    def inner(a, b):  # 要修饰的函数带有参数
        print('-----日志信息:正在努力计算中....-----')
        fn(a, b)  # fn(a, b) 等同于 sum_num(num1, num2)

    return inner


@message
def sum_num(num1, num2):
    print(num1 + num2)


# 这里实际调用的不是sum_num函数,而是inner函数,所以在inner函数中需要添加位置参数
sum_num(10, 20)

5、装饰器修饰带有不定长参数的函数

def message(fn):
    def inner(*args, **kwargs):
        print('----日志信息:正在努力计算....----')
        fn(*args, **kwargs)

    return inner


def sum_num(*args, **kwargs):
    sum1 = 0
    for i in args:
        sum1 += i
    for value in kwargs.values():
        sum1 += value
    print(sum1)


sum_num(10, 20, a=30, b=20)

6、装饰修饰带有返回值的函数

def message(fn):
    def inner(num1, num2):  # 在inner函数就没有返回,输出print()只能得到None
        print('----输入日志:正在努力计算....----')
        # fn(num1, num2)  # =》 func(10,20) => 30 并不会得到返回值
        return fn(num1, num2)

    return inner


@message
def func(num1, num2):
    result = num1 + num2
    return result


print(func(10, 20))  # func(10,20) => inner(10,20) =>需要在inner函数输入返回值

7、(重点)通用装饰器的编写

① 有嵌套 ② 有引用 ③ 有不定长参数 ④ 有return返回值 ⑤ 返回内部函数的地址

def message(fn):
    def inner(*args, **kwargs): 
        print('----日志信息:正在努力计算....----')
        return fn(*args, **kwargs)  

    return inner


@message
def sum_num(num1, num2):
    result = num1 + num2
    return result


print(sum_num(10, 20))

8、带有参数的装饰器

定义:在使用装饰器 装饰函数的时候可以传入指定参数,让装饰器内部使用。

语法:@装饰器(参数....)

实现方法:由于装饰器函数只能有一个参数,就是被装饰函数引用,所以实现方法就是“将装饰器放进一个函数内部,外部函数接收参数,给装饰器使用

def decoration(flag): # 再套入一层函数
    def message(fn):
        def inner(*args, **kwargs):
            if flag == '+':
                print('----输出日志:正在进行加法运算----')
            elif flag == '-':
                print('----输出日志:正在进行减法运算----')
            return fn(*args, **kwargs)

        return inner

    return message  # 都需要返回内层函数


@decoration('+')
def sum_num(num1, num2):
    return num1 + num2


@decoration('-')
def sub_num(num1, num2):
    return num1 - num2


print(sum_num(10, 20))
print(sum_num(20, 10))

9、类装饰器

类装饰器的编写规则:

① 必须要有一个__init__初始化方法,用于接收要装饰函数的函数

② 必须要把这个类转化为可以调用的函数 ( __call__())

class Check(object):
    # fn就是要装饰函数的名称,当Check装饰器类被调用时,系统自动将comment函数传递给comment变量
    def __init__(self, fn):
        self.__fn = fn

    def __call__(self, *args, **kwargs):
        # 编写装饰器代码
        print('登陆功能')
        # 调用comment函数本身
        self.__fn(*args, **kwargs)


# 编写一个函数实现评论功能,底层comment = Check(comment)
@Check
def comment():
    print('评论功能')

comment()
posted @   七落安歌  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示