gpt4 book ai didi

decorator - 如何创建可以包装协程或函数的Python装饰器?

转载 作者:行者123 更新时间:2023-12-04 15:31:00 27 4
gpt4 key购买 nike

我试图做一个装饰器来包装协程或函数。

我尝试的第一件事是在包装器中编写一个简单的重复代码:



def duration(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_ts = time.time()
result = func(*args, **kwargs)
dur = time.time() - start_ts
print('{} took {:.2} seconds'.format(func.__name__, dur))
return result

@functools.wraps(func)
async def async_wrapper(*args, **kwargs):
start_ts = time.time()
result = await func(*args, **kwargs)
dur = time.time() - start_ts
print('{} took {:.2} seconds'.format(func.__name__, dur))
return result

if asyncio.iscoroutinefunction(func):
return async_wrapper
else:
return wrapper


这行得通,但我想避免重复代码,因为这并不比编写两个单独的装饰器好得多。

然后我尝试使用类制作装饰器:

class SyncAsyncDuration:
def __init__(self):
self.start_ts = None

def __call__(self, func):
@functools.wraps(func)
def sync_wrapper(*args, **kwargs):
self.setup(func, args, kwargs)
result = func(*args, **kwargs)
self.teardown(func, args, kwargs)
return result

@functools.wraps(func)
async def async_wrapper(*args, **kwargs):
self.setup(func, args, kwargs)
result = await func(*args, **kwargs)
self.teardown(func, args, kwargs)
return result

if asyncio.iscoroutinefunction(func):
return async_wrapper
else:
return sync_wrapper

def setup(self, func, args, kwargs):
self.start_ts = time.time()

def teardown(self, func, args, kwargs):
dur = time.time() - self.start_ts
print('{} took {:.2} seconds'.format(func.__name__, dur))


在某些情况下,这对我来说效果很好,但是在此解决方案中,我无法将函数放入with或try语句中。
有什么方法可以创建装饰器而不重复代码?

最佳答案

也许可以找到更好的方法,但是,例如,您可以将包装逻辑移至某个上下文管理器以防止代码重复:

import asyncio
import functools
import time
from contextlib import contextmanager


def duration(func):
@contextmanager
def wrapping_logic():
start_ts = time.time()
yield
dur = time.time() - start_ts
print('{} took {:.2} seconds'.format(func.__name__, dur))

@functools.wraps(func)
def wrapper(*args, **kwargs):
if not asyncio.iscoroutinefunction(func):
with wrapping_logic():
return func(*args, **kwargs)
else:
async def tmp():
with wrapping_logic():
return (await func(*args, **kwargs))
return tmp()
return wrapper

关于decorator - 如何创建可以包装协程或函数的Python装饰器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44169998/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com