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不是函数,说明就是正常的装饰器,就按照正常的装饰器声明即可。
相关推荐
kfaino23 分钟前
码农的AI翻身(六)你好,我叫 Parameter
后端·aigc
掘金者阿豪26 分钟前
把业务数据变成共享仪表盘:Metabase可视化与远程访问实践
前端·后端
猪猪拆迁队1 小时前
虚拟工厂仿真引擎的架构设计:让一条产线可编程、可观测、可干预
后端·ai编程
字节跳动数据库2 小时前
文章分享——相似函数处理方法
人工智能·后端·程序员
云技纵横2 小时前
@Transactional 失效的 7 种场景:第 5 种最难排查
后端
用户6757049885022 小时前
你知道 Go 结构体和结构体指针调用的区别吗?一文带你彻底搞懂!
后端·go
程序员cxuan2 小时前
读懂 Claude Code 架构分析系列,第一篇,开始!
人工智能·后端·架构
用户6757049885023 小时前
面试官问“装饰器模式”,这样回答薪资多要 3000!
后端
tntxia3 小时前
Geo Scene域名修改引起的一些问题
后端
用户298698530143 小时前
Java 实现 Word 文档加密与权限解除
java·后端