装饰器用法

一、前言

学习装饰器之前,我们先了解下闭包。
有时候我们想读取函数内部的变量,该怎么实现呢?如下

def wrapper():
    n=100

print(n)

结果:NameError: name 'n' is not defined

很明显报错了,那我们要实现这个需求该怎么做呢?用闭包
闭包:能够读取外部函数内的变量的函数,如下

def wrapper():
    n=100
    def inner():
        print(n)

inner函数就是闭包,它能够读取wrapper函数内部的n变量
我们怎么执行上面程序来验证inner确实可以读取wrapper函数内部的n变量?

def wrapper():
    n=100
    def inner():
        print(n)
    return inner
test=wrapper()
test()

结果:100
我们发现确实是可以读取wrapper函数内部的n变量,并且wrapper()是一个特殊的变量,可以赋给另一个变量。因此我们可以引申到一个叫“装饰器”的概念

二、装饰器

假如我们有个需求如下:
要求每个函数执行之前记录一次日志,每个函数执行之后记录一次日志,我们可以怎么实现呢?

def open_web():
    print("打开网页......")


def fun1():
    print("执行前日志......")
    open_web()
    print("执行后日志......")


这样看视乎没问题,但是我们有十几个、几百个函数呢?有没有更优雅的写法?这时候就需要用到装饰器了

装饰器雏形:

def open_web():
    print("打开网页......")

def input():
    print("输入账号,密码......")


def wrapper(fun):
    def inner():
        print("执行前日志......")
        fun()
        print("执行后日志......")
    return inner

#wrapper()返回inner变量,open_web()就等于执行inner()函数
open_web=wrapper(open_web)
open_web()

结果:

执行前日志......
打开网页......
执行后日志......

这样看视乎没啥差别啊,python给我们提供了个语法糖

@wrapper             
def fun() 

=>等同于 fun=wrapper(fun)
wrapper()赋给fun变量,fun()就等于执行wrapper内的inner()函数,因此可以改造为如下:

def wrapper(fun):
    def inner():
        print("执行前日志......")
        fun()
        print("执行后日志......")
    return inner

@wrapper
def open_web():
    print("打开网页......")

@wrapper
def input():
    print("输入账号,密码......")


open_web()
print("-"*12)
input()

结果:

执行前日志......
打开网页......
执行后日志......
------------
执行前日志......
输入账号,密码......
执行后日志......

如果被装饰的函数有返回值呢?

def wrapper(fun):
    def inner():
        print("执行前日志......")
        res=fun()               #如果被装饰函数有返回值则赋值给res,返回
        print("执行后日志......")
        return res
    return inner

如果被装饰的函数有些有参数,有些不用参数呢?,那么我们可以写一个通用装饰器

def wrapper(fun):
    def inner(*args,**kwargs):                #组装动态参数
        print("执行前日志......")
        res=fun(*args,**kwargs)               #拆包动态参数
        print("执行后日志......")
        return res
    return inner

@wrapper
def open_web(url='www.baidu.com'):
    print(f"打开网页{url}......")
    return "百度"

@wrapper
def input(username="xian",password='123'):
    print(f"输入账号{username},密码{password}......")


open_web_res=open_web()
print("-"*12)
input_res=input()
print(open_web_res)
print(input_res)

结果如下:

执行前日志......
打开网页www.baidu.com......
执行后日志......
------------
执行前日志......
输入账号xian,密码123......
执行后日志......
百度
None

装饰器需要传参,又怎么写?需要在装饰器外面再套一层

def outer(*args,**kwargs):
    print(f"传进来的为",*args,**kwargs)
    def wrapper(fun):
        def inner(*args,**kwargs):                #组装动态参数
            print("执行前日志......")
            res=fun(*args,**kwargs)               #拆包动态参数
            print("执行后日志......")
            return res
        return inner
    return wrapper


'''
1.@outer(),会先执行outer(),outer()函数return wrapper 
2.@wrapper就变成原来的装饰器
3.@wrapper
 def open_web     变成open_web= wrapper(open_web)
4.所以open_web()变成执行inner函数,即经过装饰的open_web()函数
''''
@outer("测试")
def open_web(url='www.baidu.com'):
    print(f"打开网页{url}......")
    return "百度"

三、总结

我们每次写装饰器,都可以写如下通用装饰器:

def wrapper(fun):
	@wraps(fun)
    def inner(*args,**kwargs):                #组装动态参数
        print("执行前操作......")
        res=fun(*args,**kwargs)               #拆包动态参数
        print("执行后操作......")
        return res
    return inner
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
装饰器Python 中一个非常强大的特性,它可以用来修改或增强函数或类的功能。装饰器本质上是一个函数,可以接收一个函数或类作为参数,并返回一个新的函数或类。装饰器通常用于在不修改函数或类本身的情况下,增加一些额外的功能或修改其行为。以下是一些常见的 Python 装饰器用法示例: 1. 函数装饰器 ```python def my_decorator(func): def wrapper(): print("Before function is called.") func() print("After function is called.") return wrapper @my_decorator def say_hello(): print("Hello!") say_hello() ``` 输出结果: ``` Before function is called. Hello! After function is called. ``` 在这个例子中,我们定义了一个为 `my_decorator` 的函数装饰器,它接收一个函数作为参数,并返回一个新的函数 `wrapper`。在 `wrapper` 函数中,我们添加了一些额外的代码,用于在函数调用之前和之后执行一些操作。然后,我们使用 `@my_decorator` 语法来装饰 `say_hello` 函数,使其在被调用时自动被 `my_decorator` 装饰器修饰。最后,我们调用 `say_hello` 函数,它会自动执行 `my_decorator` 装饰器中定义的操作。 2. 类装饰器 ```python class MyDecorator: def __init__(self, func): self.func = func def __call__(self): print("Before function is called.") self.func() print("After function is called.") @MyDecorator def say_hello(): print("Hello!") say_hello() ``` 输出结果: ``` Before function is called. Hello! After function is called. ``` 这个例子中,我们定义了一个为 `MyDecorator` 的类装饰器,它接收一个函数作为参数,并重载了 `__call__` 方法。在 `__call__` 方法中,我们添加了一些额外的代码,用于在函数调用之前和之后执行一些操作。然后,我们使用 `@MyDecorator` 语法来装饰 `say_hello` 函数,使其在被调用时自动被 `MyDecorator` 装饰器修饰。最后,我们调用 `say_hello` 函数,它会自动执行 `MyDecorator` 装饰器中定义的操作。 3. 带参数的装饰器 ```python def repeat(num): def my_decorator(func): def wrapper(): for i in range(num): print("Before function is called.") func() print("After function is called.") return wrapper return my_decorator @repeat(num=3) def say_hello(): print("Hello!") say_hello() ``` 输出结果: ``` Before function is called. Hello! After function is called. Before function is called. Hello! After function is called. Before function is called. Hello! After function is called. ``` 在这个例子中,我们定义了一个为 `repeat` 的装饰器工厂函数,它接收一个参数 `num`,并返回一个新的函数装饰器 `my_decorator`。在 `my_decorator` 装饰器中,我们定义了一个新的函数 `wrapper`,它会重复执行被装饰的函数 `num` 次。然后,我们使用 `@repeat(num=3)` 语法来装饰 `say_hello` 函数,使其在被调用时自动被 `repeat` 装饰器修饰,并传递参数 `num=3`。最后,我们调用 `say_hello` 函数,它会自动执行 `repeat` 装饰器中定义的操作,重复执行 `say_hello` 函数三次。 以上是 Python 装饰器的一些常见用法装饰器Python 中非常强大的特性,可以用于各种场景,如日志记录、性能分析、缓存处理等。学会使用装饰器可以让你的代码更加简洁、易读和易于维护。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值