只是为了好玩,我决定尝试写一些类似的@cache东西functools。装饰器检查是否已经使用相同的参数执行了相同的函数。如果是,则返回已经计算的结果。
def decor(func):
cashe = dict()
def wrapper(*args, **kwargs):
key = f"{func}"
for item in args:
key += str(hash(str(item)))
for key_item in kwargs:
key += str(hash(str(key_item)))
if key not in cashe:
print('Создал!')
result = func(*args, **kwargs)
cashe[key] = result
else:
print('Взял из кеша!')
result = cashe[key]
return result
return wrapper
总的来说,我认为我们可以坐下来让它更简洁/更快/更短,但这不是现在的重点。
当我使用
@decor
def check(a, b, c=0):
return a + b + c
check(1, 5) # Создал
check(1, 5) # Взял из кеша
一切都按我的预期进行,但是当
check(1, 5, 0) # Создал
check(1, 5) # Создал
为什么会发生这种情况?c毕竟,在这两种情况下它都是不可变的并且都等于 0,但是为什么这些函数被认为是不同的呢?
因为你的装饰器只查看实际参数。它具体包含两组参数:(1, 5, 0) 和 (1, 5) - 这是两组不同的参数,相应地,缓存中的键也不同。默认参数仅在调用函数本身时添加到实际参数集中,而不是在调用装饰器添加的“包装器”时添加。
您需要使用内省,并提取有关函数默认参数的信息,将它们添加到实际参数中。
传递命名参数的示例:
结论:
也可以用位置参数来实现,也许我稍后会添加它(但这不确定)。