python有参装饰器如果实现默认参数可调用

问题产生

现在我有一个装饰器,目的是可以延迟执行某个函数。

python 复制代码
def delay(timeout: int = 1):
    def inner_func(func):
        def execute(*args, **kwargs):
            time.sleep(timeout)
            return func(*args, **kwargs)
        return execute
    return inner_func

@delay
def run_task():
    print("finished")

run_task()

看着完美无缺,肉眼看着应该是延迟1s打印finished,但是运行的时候告诉我:

TypeError: delay.<locals>.inner_func() missing 1 required positional argument: 'func'

Holyshit!!!!!

告诉我inner_func第一个参数缺失?我就纳闷的,这个为什么会缺失呢?这个不是待执行的函数吗?

然后我就debug,在def delay第一行打印了一下timeout的值

python 复制代码
def delay(timeout: int = 1):
    print(timeout)

输入结果是<function run_task at 0x10339fe20>

好的人傻了,原来是因为@delay这个写法,如果不加()会把接下来要运行的函数作为参数传入。

可以理解为当写@delay的时候,第一个参数实际上是def run_task

而当写@delay() 或者 delay(1) 或者 delay(timeout=2)的时候,才是按照我们声明的顺序来的

如何解决

我的解决方案是:

python 复制代码
import time
from typing import Callable, Optional


def delay(fn: Optional[Callable] = None, /, *, timeout: int = 1):
    """
    :param fn:      
    :param timeout: 
    :return: 
    """
    def inner_func(func):
        def execute(*args, **kwargs):
            time.sleep(timeout)
            return func(*args, **kwargs)

        return execute

    if callable(fn):
        return inner_func(fn)
    if fn is not None:
        raise Exception("装饰器的参数必须以key-value的形式进行传递")
    return inner_func


@delay
def run_task():
    print("finished")

run_task()

既然有参装饰器的第一个参数是可变的,我干脆不用第一个值了,就直接用fn作为位置参数给他占着。 并且fn后面的参数必须声明为k-v的形式(虽然说写的时候稍微麻烦了一点,但是阅读方便啊)

那么就有两种case:

  1. 如果fn是一个函数,那么说明是用@delay方式声明的,fn肯定就是待执行的方法,那么直接把fn传给inner_func即可
  2. 如果fn不是函数,说明就是正常的装饰器,就按照正常的装饰器声明即可。
相关推荐
考虑考虑13 分钟前
arthas使用
java·运维·后端
李昊哲小课31 分钟前
Spring Boot 4 旅游主题实战教程 阶段三:数据持久化
spring boot·后端·mybatis·旅游
AI 编程助手GPT35 分钟前
Bun 1.4 正式发布:从 Zig 改写为 Rust,内置浏览器、图片处理和并行测试
开发语言·人工智能·后端·ai·chatgpt
IT_陈寒1 小时前
Redis大KEY删除慢到手抖,这几个方法让我少熬一夜
前端·人工智能·后端
步行cgn1 小时前
传统 SSM 与 Spring Boot 开发对比:从配置地狱到约定优于配置
java·spring boot·后端
JavaGuide3 小时前
一个 SKILL.md 拿下 2.3 万 Star:让 Codex/Claude Code 少说废话、先给答案
前端·后端
陈随易10 小时前
pm2 替代品,nodejs&bun 线上部署必备工具
前端·后端·程序员
丘山一郎11 小时前
Spring 中的IOC控制反转 和DI依赖注入
java·后端·spring
码视野11 小时前
基于 Spring Boot + Vue3 的【大学英语四六级 (CET-4/6) 作文智能评分与句式润色系统】设计与实现(含PRD/三端高保真源码/大屏)
java·前端·人工智能·spring boot·后端·vue3
MetaLite11 小时前
Spring-AOP自调用为什么失效-AopContext真能解决吗
java·后端·spring