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不是函数,说明就是正常的装饰器,就按照正常的装饰器声明即可。
相关推荐
小王不爱笑1321 天前
Spring AOP(AOP+JDBC 模板 + 转账案例)
java·后端·spring
Python私教1 天前
Rust基本语法
后端
Python私教1 天前
Rust环境搭建
后端
jakeswang1 天前
ServletLess架构简介
java·后端·servletless
夕颜1111 天前
如何让 AI 按照你的预期输出
后端
q***56381 天前
Spring Boot--@PathVariable、@RequestParam、@RequestBody
java·spring boot·后端
q***57501 天前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
猪猪拆迁队1 天前
前端图形引擎架构设计:双引擎架构设计
前端·后端·架构
GISer_Jing1 天前
Node.js 开发实战:从入门到精通
javascript·后端·node.js
q***51891 天前
Spring Boot 条件注解:@ConditionalOnProperty 完全解析
java·spring boot·后端