装饰器相关使用

每日分享:

生活总是让我们遍体鳞伤,可是后来,那些受伤的地方一定会变成我们最强壮的地方。

目录

一、装饰器

1. 装饰器的定义

2. 装饰器示例代码

3. 装饰器的语法糖写法

二、装饰器的使用

1. 装饰器的使用场景

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

三、通用装饰器的使用

1. 装饰带有参数的函数

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

3. 装饰带有不定长参数的函数

4. 通用装饰器(不定长参数以及有返回值)

四、多个装饰器的使用

五、带有参数的装饰器

六、类装饰器


一、装饰器

1. 装饰器的定义

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

装饰器的功能特点:

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

2. 装饰器示例代码

# 装饰器实质上就是闭包,怎么判断装饰器:当闭包函数只有一个参数,并且该参数是函数类型,那么这就是一个装饰器
def func_out(func):
    def inner():
        print('登录了吗,就说话?')
        func()
        print('赶快登录')
    return inner


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


# 为了保证调用时名称不变,将闭包对象命名为函数同名
comment = func_out(comment)
comment()
  • 闭包函数有且只有一个参数,必须是函数类型,这样定义的函数才是装饰器
  • 写代码要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展

3. 装饰器的语法糖写法

如果有多个函数都需要拓展功能,每次都需要编写comment = func_out(comment)这样的代码对已有函数进行装饰,就会比较麻烦。

所以就有了语法糖,其书写格式为:@装饰器名字

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

# 装饰器实质上就是闭包,怎么判断装饰器:当闭包函数只有一个参数,并且该参数是函数类型,那么这就是一个装饰器
def func_out(func):
    def inner():
        print('登录了吗,就说话?')
        func()
        print('赶快登录')
    return inner


@ func_out
def comment():
    print("发表评论")


# 为了保证调用时名称不变,将闭包对象命名为函数同名
# comment = func_out(comment)
comment()

可以发现,结果一模一样

说明:

  • @装饰器名 就等价于 comment = func_out(comment)
  • 装饰器的执行时间是加载模块时立即执行

二、装饰器的使用

1. 装饰器的使用场景

  1. 函数执行时间的统计
  2. 输入日志信息

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

import time


def decorator(func):
    def inner():
        begin = time.time()
        func()
        end = time.time()
        print("函数运行的时间:", end-begin)
    return inner


@decorator
def work():
    for i in range(10000):
        print(i)


work()

所以,装饰器可以在不改变函数源代码及调用方式的前提下,扩展函数功能

三、通用装饰器的使用

1. 装饰带有参数的函数

def decorator(func):
    def inner(a, b):
        print("正在努力计算中...")
        func(a, b)
    return inner


@decorator
def add_num(num1, num2):
    result = num1 + num2
    print(result)


add_num(1, 2)


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

# --------------------装饰器装饰带有返回值的函数----------------------
def decorator(func):
    def inner(a, b):
        print("正在努力计算中...")
        sum1 = func(a, b)
        return sum1
    return inner


@decorator
def add_num(num1, num2):
    result = num1 + num2
    return result


sum2 = add_num(1, 2)
print(sum2)

3. 装饰带有不定长参数的函数

# --------------------装饰器装饰带有不定参数的函数---------------------------------
def decorator(func):
    def inner(*args, **kwargs):
        print("正在努力计算中...")
        func(*args, **kwargs)
    return inner


# *args:把元组里面的每一个元素,按照位置参数的方式进行传参
# **kwargs:把字典里面的每一个键值对,按照关键字的方式进行传参
@decorator
def add_num(*args, **kwargs):
    result = 0
    for value in args:
        result += value
    for value in kwargs.values():
        result += value
    print(result)


add_num(1, 2, a=3)

4. 通用装饰器(不定长参数以及有返回值)

# --------------------通用装饰器---------------------------------
def decorator(func):
    def inner(*args, **kwargs):
        print("正在努力计算中...")
        num = func(*args, **kwargs)
        return num
    return inner


@decorator
def show():
    return "你好!"


info = show()
print(info)

通过以上几类装饰器的书写,可以发现:

装饰器的内部函数inner与要装饰的函数保持一致即可,即装饰函数有参数,inner就有参数;装饰函数有返回值,inner就有返回值

四、多个装饰器的使用

def add_p(func):
    def inner():
        result = "<p>" + func() + "</p>"
        return result
    return inner


def add_div(func):
    def inner():
        result = "<div>" + func() + "</div>"
        return result
    return inner


@add_div
@add_p
def content():
    return "人生苦短,我学python"


print(content())

说明:

  • 多个装饰器的装饰:离函数最近的装饰器先装饰,然后外面的装饰器再对装饰后的函数进行装饰

五、带有参数的装饰器

带有参数的装饰器就是使用装饰器装饰函数的时候可以传入指定参数

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

在装饰器外面包裹上一个函数,让最外面的函数接收参数,返回的是装饰器

def logging(flag):
    def decorator(func):
        def inner(a, b):
            if flag == "+":
                print("正在进行加法运算...")
            elif flag == "-":
                print("正在进行减法运算...")
            result = func(a, b)
            return result
        return inner
    return decorator


@logging("+")
def add(a, b):
    result = a + b
    return result


@logging("-")
def sub(a, b):
    result = a - b
    return result


print(add(1, 2))
print(sub(1, 3))

使用带有参数的装饰器,其实是在装饰器外面又包裹了一个函数,使用该函数接收参数,返回装饰器(@符号必须配合装饰器使用)

六、类装饰器

装饰器还有一种特殊的用法就是类装饰器,就是通过定义一个类来装饰函数

class Check(object):

    def __init__(self, func):
        # 初始化操作在此完成(将func设为私有)
        self.__func = func

    # 实现call方法,表示对象是一个可调用对象,可以像调用函数一样进行调用
    def __call__(self, *args, **kwargs):
        # 添加装饰功能
        print("请先登录")
        self.__func()


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


comment()

说明:

  • @Check等价于comment = Check(comment),所以需要提供一个init方法,并多增加一个func参数
  • 要想类的实例对象能够像函数一样调用,需要在类里面使用call方法,把类的实例变成可调用对象,也就是说可以像函数一样调用
  • 在call方法里对func函数进行装饰,可以添加额外的功能
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值