python考点-装饰器

一.装饰器概念

装饰器是一个高阶函数,可以动态修改函数或类的行为,例如日志记录,性能分析,权限控制和缓存。

装饰器概念:本质上是一个函数,它可以接收一个函数作为参数并返回一个新的函数。这个函数是对原函数的“包装”和“增强”,可以在不改变原函数代码的前提下,增加额外的功能。

装饰器工作过程:

  1. 定义装饰器:定义一个装饰器函数,该函数接收一个函数作为参数。
  2. 定义内部函数:在装饰器函数内部定义一个函数(wrapper),这个函数会调用原函数,并且在调用前后添加其他功能。
  3. 返回内部函数:装饰器函数返回内部函数。
  4. @语法:在需要被装饰的函数前使用@装饰器名称,Python解释器会自动将函数名作为参数传递给装饰器函数,并返回新的函数。

二.装饰器的应用

1.原函数带参数

import time

def decorator(func): # 装饰器函数
    def wrapper(*args, **kwargs):  #内部函数
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f'{func.__name__} execution time: {end_time-start_time} seconds')
    return wrapper

@decorator
def square(x):# 原函数
    res = x**2
    print(res)
    return res

square(10) #调用函数
"""
100
square execution time: 2.5987625122070312e-05 seconds
"""

装饰器函数decorator,输出函数运行时间,如果被装饰的函数带参数,装饰器内部的函数wrapper可以接收,通过*args和**kwargs实现。

2.带参数的装饰器

使用一个外层函数封装装饰器,可以向装饰器本身传递参数,依据不同的条件实现不同的装饰器功能。

import time
def timer(threshold):  # 外层函数
    def decorator(func):  # 装饰器函数
        def wrapper(*args, **kwargs):  # 内部函数
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            if end_time - start_time > threshold: # 条件
                print(f'{func.__name__} took longer than {threshold} seconds')
            return result
        return wrapper
    return decorator

@timer(0.2)  # 等价于 my_sleep = timer(0.2)(my_sleep)
def my_sleep():
    time.sleep(0.4)

my_sleep() # square took longer than 0.2 seconds

3.functool.wraps

 print(my_sleep.__name__)  # 打印函数名称 wrapper

 装饰后函数元数据会丢失(如函数名称,文档字符串等), 如果想要保留这些元数据,可以使用functool.wraps装饰器。

import functools

def decorator(func): # 装饰器函数
    @functools.wraps(func)
    def wrapper(*args, **kwargs):  #内部函数
        func(*args, **kwargs)        
    return wrapper

@decorator
def square(x):
    print('This is a decorated function')

print(square.__name__)  # square

装饰器的优点:提高了代码的可重用性,避免重复冗余代码,

4.类装饰器

装饰器不一定是函数,也可以是类,使用方法和函数类似。

类装饰器中,__call__魔术方法实现对原函数的调用和额外的逻辑代码编写。

class logging(object):   # 装饰器类
    def __init__(self, func):  # 传递的是test方法
        self.func = func

    def __call__(self, *args, **kwargs):  # 接受任意参数
        print("{} is running.".format(self.func.__name__))
        return self.func(*args, **kwargs)

@logging
def test(a, b):
    print(a+b)

test(2, 7)
"""
test is running.
9
"""

类作为一个装饰器,首先使用__init__方法实例化函数,实例化func后,使用self.func即可调用函数,然后调用__call__装饰函数。

类装饰器也可以传递参数,使用__init__魔术方法 。

from functools import wraps

class logging(object):
    def __init__(self, logfile="day.log"):  # 传递装饰器参数
        self.logfile = logfile

    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(self.logfile)
            return func(*args, **kwargs)
        return wrapper

@logging(logfile='day1.log')
def test(num):
    print(num)

test(10)
"""
day1.log
10
"""

5.装饰器顺序

一个函数可以同时定义多个装饰器,例如:

@d1
@d2
@d3
def func():
    print('A sample')

多个装饰器的执行顺序是从里到外,先调用最里面的装饰器,再调用最外层的装饰器,等价于:

f = d1(d2(d3(func)))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值