【问题标题】:How to know what values were passed to function?如何知道传递给函数的值是什么?
【发布时间】:2021-01-28 14:41:04
【问题描述】:
def warn_slow(func):
    def wrapper(*args, **kwargs):
        start_time=time.time()
        func(*args,**kwargs)
        time_elapsed=time.time()-start_time
        if time_elapsed>2:
            return (f"execution of {func.__name__} with {func.__code__.co_names} arguments took more than 2 seconds")
    return wrapper

我想编写一个装饰器来计算函数执行的时间,如果超过 2 秒,将返回文本“使用 {function variables} 参数执行 {func.__name__} 耗时超过 2 秒”。我们如何知道作为参数传递的值是什么?我试过func.__code__.co_names,但它只返回参数名称。

【问题讨论】:

标签: python


【解决方案1】:

您可以通过将@warvariuc's answer 与问题Decorator that prints function call details (parameters names and effective values)? 合并到您自己的装饰器中来做这样的事情:

import inspect
import time

def warn_slow(func):
    '''Decorator that warns when a call to the function takes too long.'''
    TIME_LIMIT = 2

    def wrapper(*args, **kwargs):
        func_args = inspect.signature(func).bind(*args, **kwargs).arguments
        func_args_str = ", ".join("{}={!r}".format(*item) for item in func_args.items())
        start_time = time.time()
        result = func(*args, **kwargs)
        time_elapsed = time.time() - start_time
        if time_elapsed > TIME_LIMIT:
            print(f"execution time of {func.__module__}.{func.__qualname__}"
                  f"({func_args_str}) took more than {TIME_LIMIT} seconds")
        return result

    return wrapper


@warn_slow
def test_func_a(a, b, c=None):
    time.sleep(1)

@warn_slow
def test_func_b(a, b, c=None):
    time.sleep(2.5)

test_func_a(1, 2, c=13)
test_func_b(3, 4, c=42)

产生的输出:

execution time of __main__.test_func_b(a=3, b=4, c=42) took more than 2 seconds

概括

在编程时,通常最好避免将常量字面值“硬编码”到代码中。在这种情况下,装饰器可以通过允许覆盖 2 秒时间限制来变得更加灵活。一种方法需要让它接受一个可选参数,指定限制应该是什么。为了实现这一点,我使用了来自@Nicole's answer 的通用“装饰器装饰器”来解决如何实现让它们这样做的问题。我选择它的部分原因是它需要对上面显示的装饰器进行最少的修改(而且它本身非常通用)。

结果如下:

import inspect
import time


def optional_arg_decorator(fn):  # From https://stackoverflow.com/a/20966822/355230
    def wrapped_decorator(*args):
        if len(args) == 1 and callable(args[0]):
            return fn(args[0])
        else:
            def real_decorator(decoratee):
                return fn(decoratee, *args)
            return real_decorator
    return wrapped_decorator


@optional_arg_decorator
def warn_slow(func, time_limit=2):
    ''' Decorator that warns when a call to the function takes too long.
            Accepts optional argument to override default time limit.
    '''
    def wrapper(*args, **kwargs):
        func_args = inspect.signature(func).bind(*args, **kwargs).arguments
        func_args_str = ", ".join("{}={!r}".format(*item) for item in func_args.items())
        start_time = time.time()
        result = func(*args, **kwargs)
        time_elapsed = time.time() - start_time
        if time_elapsed > time_limit:
            print(f"execution time of {func.__module__}.{func.__qualname__}"
                  f"({func_args_str}) took more than {time_limit} seconds")
        return result
    return wrapper


@warn_slow
def test_func_a(a, b, c=None):
    time.sleep(1)

@warn_slow
def test_func_b(a, b, c=None):
    time.sleep(2.5)

@warn_slow(3)  # Override default time limit.
def test_func_c(a, b, c=None):
    time.sleep(3.1)

test_func_a(1, 2, c=10)
test_func_b(3, 4, c=2)
test_func_c(5, 6, c=42)

输出:

execution time of __main__.test_func_b(a=3, b=4, c=2) took more than 2 seconds
execution time of __main__.test_func_c(a=5, b=6, c=42) took more than 3 seconds

【讨论】:

    【解决方案2】:

    装饰器返回的函数将采用 任意 参数。这些将直接传递给被修饰的函数,并用于构造您的字符串。

    def decorator(f):
        def _(*args, **kwargs):
            t = time.time()
            result = f(*args, **kwargs)
            duration = time.time() - t
            print(f"{f.__name__} with {", ".join(*args)} took {t} seconds")
            return result
        return _
    

    我把它作为一个练习,为**kwargs 构造一个适当的字符串,并将其包含在时间消息中。

    【讨论】:

      猜你喜欢
      • 2021-06-28
      • 1970-01-01
      • 2020-04-13
      • 2013-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-27
      • 1970-01-01
      相关资源
      最近更新 更多