python - 如何知道传递给函数的值是什么?
问题描述
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
了,但是它只返回参数名称。
解决方案
您可以通过合并@warvariuc 对打印函数调用详细信息(参数名称和有效值)的装饰器问题的回答来做类似的事情?因此进入你自己的装饰器:
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回答中的通用“装饰器装饰器”来回答关于如何实现让它们这样做的问题。我选择它的部分原因是它需要对上面显示的装饰器进行最少的修改(并且它本身非常通用)。
结果如下:
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
推荐阅读
- oracle - 在 oracle 中创建作业时出现编译错误
- clojure - 计算列表中项目之间的增量
- c++ - OpenCl 中的“CL_DEVICE_NOT_FOUND”
- java - 编译java程序时遇到问题,没有生成类文件
- here-api - 计算矩阵:行人路线的 walkSpeed 参数
- javascript - 我们应该如何从 AngularJS 1.6.4 升级到最新的 Angular 版本?
- angular - 无法理解亲子沟通
- javascript - Javascript尝试根据内部对象数组值对对象数组进行排序
- html - 使 img 忽略父填充并在响应时以负边距与容器边缘齐平
- azure-devops - Azure DevOps YAML 并行运行未排队