Python 定义一个属性可由用户修改的装饰器

需求

我们想编写一个装饰器来包装函数,但是可以让用户调整装饰器的属性,这样在运行时能够控制装饰器的行为

解决方案

下面给出的解决方案对上一节的示例进行了扩展,引入了访问器函数(accessor function),通过使用nonlocal关键字声明变量来修改装饰器内部的属性。之后把访问器函数作为函数属性附加到包装函数上

python 复制代码
import logging
from functools import partial, wraps


# Utility decorator to attach a function as an attribute of obj
def attach_wrapper(obj, func=None):
    if func is None:
        return partial(attach_wrapper, obj)
    setattr(obj, func.__name__, func)
    return func

def logged(level, name=None, message=None):
    '''
    Add logging to a function. level is the logging
    level, name is the logger name, and message is the
    log message. If name and message aren't specified,
    they default to the function's module and name.
    '''
    def decorate(func):
        logname = name if name else func.__module__
        log = logging.getLogger(logname)
        logmsg = message if message else func.__name__

        @wraps(func)
        def wrapper(*args, **kwargs):
            log.log(level, logmsg)
            return func(*args, **kwargs)

        # Attach setter functions
        @attach_wrapper(wrapper)
        def set_level(newlevel):
            nonlocal level
            level = newlevel

        @attach_wrapper(wrapper)
        def set_message(newmsg):
            nonlocal logmsg
            logmsg = newmsg

        return wrapper
    return decorate

# Example use
@logged(logging.DEBUG)
def add(x, y):
    return x + y

@logged(logging.CRITICAL, 'example')
def spam():
    print('Spam!')

logging.basicConfig(level=logging.DEBUG)
add(2, 3) #DEBUG:__main__:add

add.set_level(logging.WARNING)
add(2, 3) #WARNING:__main__:add

关键就在访问器函数(即,set_message()和set_level()),它们以属性的形式附加到了包装函数上。每个访问器函数允许对nonlocal变量赋值来调整内部参数

attach_wrapper 分析如下

def attach_wrapper(obj, func=None):

这是函数的定义部分。它接受两个参数:

obj: 要将函数附加到的对象

func: 要附加的函数,默认为 None

  • if func is None:

    如果 func 参数为 None,说明用户只传递了 obj 参数。

    在这种情况下,attach_wrapper 函数返回一个新的偏函数(partial function),它接受一个 func 参数。这个偏函数会将传递给它的 func 附加到 obj 上。

    setattr(obj, func.name, func)

  • 如果 func 参数不为 None,说明用户同时传递了 obj 和 func 参数。

    这行代码将 func 函数附加到 obj 对象上,函数名称为 func.name

    return func

最后,这个装饰器函数返回传入的 func 函数本身。

相关推荐
2601_951643775 小时前
Python第一,Java跌出前三,C语言杀回来了
java·c语言·python·编程语言排行·技术趋势
AC赳赳老秦7 小时前
OpenClaw+Power Apps 实战:自动生成 Power Apps 应用、连接 Excel 数据源
大数据·开发语言·python·serverless·excel·deepseek·openclaw
茉莉玫瑰花茶8 小时前
综合案例 - AI 智能租房助手 [ 5 ]
服务器·数据库·人工智能·python·ai
文艺倾年8 小时前
【强化学习】强化学习基本概念,20W字总结(一)
人工智能·python·语言模型·自然语言处理·面试·职场和发展·大模型
宸丶一8 小时前
Day 13:持久化记忆 - 让 Agent 拥有长期记忆
jvm·python·ai
码云骑士9 小时前
13-列表append的底层真相(上)-listobject源码中的预分配策略
开发语言·python
浦信仿真大讲堂9 小时前
达索系统SIMULIA Abaqus 2026接触和约束的增强新功能介绍
人工智能·python·算法·仿真软件·达索软件
xufengzhu9 小时前
第三方 Python 库 Loguru 的进阶实战
python·loguru
极光代码工作室10 小时前
基于深度学习的手写数字识别系统
人工智能·python·深度学习·神经网络·机器学习
geovindu10 小时前
python: speech to text offline
开发语言·python·语音识别