@my_decorator装饰器的使用教程

1. 什么是装饰器?

@装饰器

装饰器定义

 装饰器是一种特殊的函数,它可以用来修改其他函数的行为。装饰器通过接受一个函数作为参数,然后返回一个新的函数来实现修改行为的功能。

 装饰器在 Python 中使用 @ 符号来定义。例如:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("开始执行函数:", func.__name__)
        result = func(*args, **kwargs)
        print("函数执行结束:", func.__name__)
        return result
    return wrapper

@my_decorator
def my_function():
    print("这是我的函数")

my_function()

在这个例子中,my_decorator 是一个装饰器,它接受 my_function 函数作为参数,然后返回一个新的函数 wrapper。当 my_function 被调用时,实际上是 wrapper 函数被执行。wrapper 函数在执行 my_function 之前和之后打印了一些信息。

如何使用装饰器

使用装饰器非常简单,只需要在要装饰的函数前面添加 @ 符号和装饰器函数的名称即可。例如:

@my_decorator
def my_function():
    print("这是我的函数")

my_function()

这等价于:

def my_function():
    print("这是我的函数")

my_function = my_decorator(my_function)

my_function()

输出:

开始执行函数: my_function
这是我的函数
函数执行结束: my_function

装饰器的优点

装饰器有以下几个优点:

  • 代码可重用性: 装饰器可以将一些通用的功能封装起来,方便重复使用。
  • 代码可读性: 装饰器可以使代码更加简洁易读。
  • 代码可维护性: 装饰器可以使代码更容易维护和修改。

装饰器的应用

装饰器可以用于各种场景,例如:

  • 计时: 记录函数执行时间。
  • 缓存: 缓存函数结果。
  • 权限控制: 限制函数的访问权限。
  • 日志记录: 记录函数执行信息。
  • 异常处理: 处理函数执行过程中出现的异常。

2. 装饰器应用举例

2.1 计时

计时装饰器,可以记录函数执行时间,方便调试和性能分析。计时装饰器会增加函数执行时间,因此不建议在生产环境中使用。

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"函数 {func.__name__} 执行时间:{end_time - start_time:.2f} 秒")
        return result
    return wrapper

@timer
def my_function():
    time.sleep(1)

my_function()

输出:

函数 my_function 执行时间:1.00 秒

2.2 缓存

可以将函数的结果缓存起来,避免重复计算,提高程序效率

import functools

def cache(func):
    cache_dict = {}
    # 使用 functools.wraps 装饰器来保留 func 的元信息,例如函数名、文档字符串等
    @functools.wraps(func) 
    def wrapper(*args, **kwargs):
        key = str(args) + str(kwargs)
        if key not in cache_dict:
            cache_dict[key] = func(*args, **kwargs)
        return cache_dict[key]
    return wrapper

@cache
def my_function(x):
    return x * x

print(my_function(3))
print(my_function(3))
#第一次调用 my_function(3) 时,由于缓存中没有结果,所以会执行 my_function 函数并将其结果存储在缓存中。

#第二次调用 my_function(3) 时,由于缓存中已经存在结果,所以直接从缓存中返回结果,不会再次执行 my_function 函数。

输出:

9
9

2.3 权限控制

可以限制函数的访问权限,确保只有具有相应权限的用户才能执行该函数

def admin_required(func):
    def wrapper(*args, **kwargs):
    #is_admin() 函数需要根据实际情况进行定义,以判断当前用户是否具有管理员权限
        if not is_admin():
            raise PermissionError("您没有权限执行此操作")
        return func(*args, **kwargs)
    return wrapper

@admin_required
def delete_user(user_id):
    # 删除用户
    pass

delete_user(123)

输出:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in wrapper
PermissionError: 您没有权限执行此操作

2.4 日志记录

使用 log 装饰器包装 my_function 函数,使其在执行前后记录日志消息

import logging

def log(func):
    def wrapper(*args, **kwargs):
        logging.info(f"开始执行函数 {func.__name__}")
        result = func(*args, **kwargs)
        logging.info(f"函数 {func.__name__} 执行结束")
        return result
    return wrapper

@log
def my_function():
    # 执行一些操作
    pass

my_function()

输出:

INFO:root:开始执行函数 my_function
INFO:root:函数 my_function 执行结束

2.5 异常处理

使用 handle_exceptions 装饰器包装 my_function 函数,使其在执行过程中捕获并处理异常

def handle_exceptions(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print(f"函数 {func.__name__} 出现异常:{e}")
    return wrapper

@handle_exceptions
def my_function():
    1 / 0

my_function()

输出:

函数 my_function 出现异常:division by zero

3. functools.wraps()使用介绍

 Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和函数属性

不加wraps

def my_decorator(func):
    def wrapper(*args, **kwargs):
        '''this is decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)

    return wrapper


@my_decorator
def example():
    """this is Docstring"""
    print('Called example function')


print('name: {}'.format(example.__name__))
print('docstring: {}'.format(example.__doc__))

输出:

name: wrapper
docstring: this is decorator

加上wraps

import functools


def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)

    return wrapper


@my_decorator
def example():
    """Docstring"""
    print('Called example function')


print('name: {}'.format(example.__name__))
print('docstring: {}'.format(example.__doc__))

输出:

name: example
docstring: this is Docstring

参考链接:
https://blog.csdn.net/weixin_43750377/article/details/115112517

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值