python通用运行时间装饰器

@wrapt.decorator
def universal(wrapped, instance, args, kwargs):
    if instance is None:
        if inspect.isclass(wrapped):
            # 装饰一个类
            # Decorator was applied to a class.
            return wrapped(*args, **kwargs)
        else:
           # 装饰一个普通函数或者静态方法
            # Decorator was applied to a function or staticmethod.
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
    else:
        if inspect.isclass(instance):
            # 装饰类方法
            # Decorator was applied to a classmethod.
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
        else:
           # 装饰实例方法
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
           
def consume_time(wrapped, args, kwargs):
    local_time = datetime.datetime.now()
    ret = wrapped(*args, **kwargs)
    times = (datetime.datetime.now() - local_time).seconds
    funcname = wrapped.name
    print(‘运行 {} 函数消耗的时间为 {} 分 {} 秒’.format(
        funcname, times // 60, times % 60))
    # print(‘Run {} time is {} minutes {} seconds’.format(
    #     funcname, times // 60, times % 60))
    return ret


既然说是通用装饰器,怎么个通用法呢?它可以作用于以下内容


* 类
* 普通函数
* 类静态方法
* 类方法
* 实例方法


接下来我们测试一下


【未加装饰器的程序】



import time

class People:
    # 定义基本属性
    name = “”
    age = 0

# 初始化函数
    def init(self, name, age):
        self.name = name
        self.age = age 
    
    # 静态方法
    @staticmethod
    def work():
        time.sleep(3)
        print(“I could work”)

# 类方法
    @classmethod
    def speak(cls, words):
        time.sleep(1)
        print(words)

# 实例方法
    def eat(self, food):
        time.sleep(5)
        print(f"I am eating {food}“)
    
# 普通函数
def read(bookname):
    time.sleep(1)
    print(f"I am reading {bookname}”)

# 调用普通函数
read(“《Linux 二进制分析》”)

# 调用静态方法
People.work()

# 调用类方法
People.speak(“hello world”)

## 调用实例方法
# 实例化一个对象
xiaoming = People(name=“xiaoming”, age=18)
xiaoming.eat(“a sandwich”)


运行后结果



![图片](https://img-blog.csdnimg.cn/img_convert/94d1c3855dfa02a91a99138d7baa185b.png)


现在我们加上时间装饰器,来看看这些函数都消耗了多少时间


【已经加上装饰器的程序】


为了演示装饰不同内容,我们给装饰器每个分支都加上 `print`



import datetime
import time
import wrapt
import inspect

@wrapt.decorator
def universal(wrapped, instance, args, kwargs):
    funcname = wrapped.name
    if instance is None:
        if inspect.isclass(wrapped):
            print(“-” * 50)
            print(“正在装饰一个类”)
            return wrapped(*args, **kwargs)
        else:
            print(“-” * 50)
            print(f"正在装饰一个普通函数或者静态方法: {funcname}“)
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
    else:
        if inspect.isclass(instance):
            print(”-" * 50)
            print(f"正在装饰类方法: {funcname}“)
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
        else:
            print(”-" * 50)
            print(f"正在装饰实例方法: {funcname}“)
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            print(”-" * 50)
            return ret

def consume_time(wrapped, args, kwargs):
    local_time = datetime.datetime.now()
    ret = wrapped(*args, **kwargs)
    times = (datetime.datetime.now() - local_time).seconds
    funcname = wrapped.name
    print(‘运行 {} 函数消耗的时间为 {} 分 {} 秒’.format(
        funcname, times // 60, times % 60))
    # print(‘Run {} time is {} minutes {} seconds’.format(
    #     funcname, times // 60, times % 60))
    return ret

@universal
class People:
    # 定义基本属性
    name = “”
    age = 0

# 初始化函数
    def init(self, name, age):
        self.name = name
        self.age = age 
    
    # 静态方法
    @universal
    @staticmethod
    def work():
        time.sleep(3)
        print(“I could work”)

# 类方法
    @universal
    @classmethod
    def speak(cls, words):
        time.sleep(1)
        print(words)

# 实例方法
    @universal
    def eat(self, food):
        time.sleep(5)
        print(f"I am eating {food}“)
    
# 普通函数
@universal
def read(bookname):
    time.sleep(1)
    print(f"I am reading {bookname}”)

# 调用普通函数
read(“《Linux 二进制分析》”)

# 调用静态方法
People.work()

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

<think>好的,我现在需要回答用户关于Python函数超时装饰器的问题。首先,我需要回忆一下装饰器的基本概念,以及如何在Python中实现超时机制。装饰器Python中用来修改或增强函数行为的一种方式,通常通过@语法糖来使用。 接下来,用户问的是超时装饰器,也就是能够限制函数执行时间装饰器。我需要考虑如何实现一个这样的装饰器。可能的思路是使用信号(signal)模块或者多线程/多进程来实现超时控制。不过,signal模块在Windows上可能不太稳定,或者有兼容性问题,而多线程的方式可能更通用一些。 首先,我应该想到使用signal.alarm函数,这在Unix-like系统上有效。当函数执行超过指定时间时,触发一个超时异常。但需要注意,signal模块在不同平台上的行为可能不同,比如Windows可能不支持某些信号。因此可能需要考虑替代方案,比如使用threading模块中的Timer来中断函数执行。 不过,直接中断一个正在运行的线程可能会有问题,因为Python的全局解释器锁(GIL)可能让线程无法被强制终止。这时候可能需要使用多进程,因为进程可以被终止而不会影响主进程。但这样会增加复杂度,因为进程间通信更麻烦。 所以,可能的实现方法有两种:基于signal的方式(适用于Unix)和基于multiprocessing的方式(跨平台)。需要向用户说明这两种方法的优缺点,并给出示例代码。 另外,Python中有没有现成的库可以实现函数超时?比如使用第三方库如wrapt、timeout-decorator等。如果有的话,也应该推荐给用户,这样他们不需要自己实现,避免潜在的错误。 在写代码示例时,需要注意装饰器的正确写法,可能需要使用functools.wraps来保留原函数的元数据。同时,处理异常的部分也需要详细说明,比如捕获超时异常后应该抛出什么样的错误,或者让用户自定义处理方式。 可能还需要提醒用户,超时装饰器在某些情况下可能无法正常工作,比如函数内部执行的是不可中断的操作(如某些IO操作),或者涉及到多线程/多进程环境下的同步问题。此外,使用信号的方法在主线程中可能有效,但在子线程中可能无法处理信号,需要特别注意。 总结下来,回答的结构应该是: 1. 介绍装饰器的概念。 2. 超时装饰器的作用:限制函数执行时间。 3. 实现方式一:使用signal模块(代码示例,适用平台)。 4. 实现方式二:使用multiprocessing模块(代码示例,跨平台)。 5. 提到第三方库,如timeout-decorator。 6. 注意事项和潜在问题。 需要确保代码示例正确,比如在signal的例子中,设置信号处理函数,然后设置alarm,在装饰器中处理超时异常。在multiprocessing的例子中,使用Process类来启动子进程,然后join超时后终止进程。 还要注意,在multiprocessing的例子中,函数参数和返回值的传递可能需要使用队列(Queue)或者其他的进程间通信方式,否则返回值可能无法正确获取。因此,在示例中需要处理如何传递参数和获取结果,或者处理可能的异常。 此外,需要测试这些代码是否存在问题,比如在装饰器中使用多进程时,如果函数有副作用或者修改了某些共享状态,可能会导致问题。因此,应该建议用户仅在必要时使用,并了解其限制。 最后,应该总结不同方法的优缺点,帮助用户根据实际情况选择适合的方案。</think>下面是对Python函数超时装饰器的分步介绍: ### 一、核心作用 通过装饰器限制函数最大执行时间,超时后自动中断执行并抛出异常。典型应用场景: - 网络请求防阻塞 - 算法执行时间限制 - 防止死循环 ### 二、实现方案对比 | 方案 | 优点 | 缺点 | |---------------------|-----------------------|------------------------------| | signal信号机制 | 实现简单 | 仅Unix系统有效 | | multiprocessing进程 | 跨平台 | 需要处理进程间通信 | | 第三方库 | 开箱即用 | 需额外安装依赖 | ### 三、原生实现示例 #### 方案1:signal信号(Unix系统) ```python import signal from functools import wraps from contextlib import contextmanager class TimeoutError(Exception): pass @contextmanager def time_limit(seconds): def signal_handler(signum, frame): raise TimeoutError("函数执行超时") signal.signal(signal.SIGALRM, signal_handler) signal.alarm(seconds) try: yield finally: signal.alarm(0) def timeout(seconds): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): with time_limit(seconds): return func(*args, **kwargs) return wrapper return decorator # 使用示例 @timeout(2) def long_running_task(): import time time.sleep(3) ``` #### 方案2:multiprocessing进程(跨平台) ```python from multiprocessing import Process, Queue from functools import wraps import time def timeout(seconds): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): result_queue = Queue() def worker(): try: result = func(*args, **kwargs) result_queue.put(('success', result)) except Exception as e: result_queue.put(('error', e)) p = Process(target=worker) p.start() p.join(timeout=seconds) if p.is_alive(): p.terminate() p.join() raise TimeoutError(f"函数执行超过 {seconds} 秒") status, data = result_queue.get() if status == 'success': return data else: raise data return wrapper return decorator # 使用示例 @timeout(3) def my_function(x): time.sleep(x) return "完成" try: print(my_function(2)) # 正常执行 print(my_function(5)) # 触发超时 except TimeoutError as e: print(e) ``` ### 四、推荐第三方库 1. **timeout-decorator** ```bash pip install timeout-decorator ``` ```python import timeout_decorator @timeout_decorator.timeout(5, timeout_exception=TimeoutError) def my_function(): # 长时间操作 ``` 2. **wrapt_timeout_decorator**(支持Windows) ```python from wrapt_timeout_decorator import timeout @timeout(5) def my_function(): # 长时间操作 ``` ### 五、注意事项 1. 信号方案在Windows下不可靠 2. 被装饰函数若涉及共享资源操作,使用进程方案可能导致数据不一致 3. 无法中断处于I/O等待状态的函数 4. 装饰器会影响原函数的元信息,建议始终使用`@wraps` ### 六、最佳实践建议 1. 优先考虑使用经过验证的第三方库 2. 超时时间设置应大于函数正常执行的最长时间 3. 配合日志记录超时事件 4. 在单元测试中验证超时逻辑 完整技术实现路线: 1. 确定目标平台(Unix/跨平台) 2. 选择实现方案 3. 添加异常处理逻辑 4. 编写单元测试验证 5. 集成到项目错误处理体系 这些方案可根据具体需求组合使用,例如:主程序使用进程方案保证跨平台,在Linux服务器环境可额外添加信号方案进行双重保护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值