这段代码的功能与functools.lru_cache完全一样。在设计、实现、风格或其他方面有什么可以改进的地方吗?(Python版本= 3.6.*)
from collections import OrderedDict
from functools import wraps
def lru_cache(maxsize=None):
def decorator(func):
cache = OrderedDict()
@wraps(func)
def decorated(*arg, **kwargs):
key = (*arg, None, *kwargs)
try:
val = cache[key]
del cache[key]
except KeyError:
val = func(*arg, **kwargs)
cache[key] = val
if maxsize and len(cache) > maxsize:
cache.popitem(last=False)
return val
return decorated
return decorator发布于 2017-06-22 12:08:48
对于如何处理kwargs,您有一个相当大的错误。
为了测试这一点,我们可以创建一个简单的函数来查看您的密钥是什么。做一些简单的测试。
def test(*args, **kwargs):
return (*args, None, *kwargs)
print(test(a=1)) # (None, 'a')
print(test(a=2)) # (None, 'a')
print(test(a=1, b=2)) # (None, 'a', 'b')
print(test(b=2, a=1)) # (None, 'b', 'a')因此,您应该对kwargs.items()进行排序。然而,要正确地将args和kwargs更改为函数所采用的单一标准,则要复杂得多。最简单的方法是使用inspect.signature获取以下内容:
def test(fn):
signature = inspect.signature(fn)
def call(*args, **kwargs):
bind = signature.bind(*args, **kwargs)
bind.apply_defaults()
return bind.args, tuple(sorted(bind.kwargs.items()))
return call
def fn1(a, b, c=1, *, d=2, **kwargs):
pass
def fn2(a, b, *args, c=1, d=2, **kwargs):
pass
# Checking that it works as intended
for fn in (fn1, fn2):
t = test(fn)
print(t('a', 'b'))
print(t('a', 'b', 'c'))
print(t(a='a', b='b', c='c'))
print(t(b='b', c='c', a='a'))
print(t('a', 'b', d='d'))
print(t('a', 'b', test='test'))
print(t('a', 'b', t1='t1', t2='t2'))
print(t('a', 'b', t2='t2', t1='t1'))所以我会用:
from collections import OrderedDict
from functools import wraps
from inspect import signature
def lru_cache(maxsize=None):
def decorator(func):
func_sig = signature(func)
cache = OrderedDict()
@wraps(func)
def decorated(*arg, **kwargs):
bind = func_sig.bind(*args, **kwargs)
bind.apply_defaults()
args, kwargs = bind.args, bind.kwargs
key = (arg, tuple(sorted(kwargs.items())))
try:
val = cache[key]
del cache[key]
except KeyError:
val = func(*arg, **kwargs)
cache[key] = val
if maxsize and len(cache) > maxsize:
cache.popitem(last=False)
return val
return decorated
return decorator添加typed也相当容易,可以归结为使用type的额外值生成更多的元组。我敢肯定你有能力这么做。
https://codereview.stackexchange.com/questions/166388
复制相似问题