我试图了解python中lru_cache decorator的实现,特别是它是如何从函数args为其内部dict创建key的。
我一直在读这个https://github.com/python/cpython/blob/master/Lib/functools.py#L414
我无法理解为什么函数中有这个kwd_mark = (object(),)。我看到它只使用一个tuple实例来生成一个object(),它看起来就像一个函数调用的key的所有args和kwargs/kwds之间的分隔符。我试着去理解它在这里做什么特别的事情,https://repl.it/repls/ExpensiveFinishedSandboxes,但是我什么都想不出来。
发布于 2018-02-23 10:43:11
链接是好的,但他们有打破的倾向,所以我会尝试把所有的东西直接包括在答案中。我们有这样一个函数(简化):
def make_key(args, kwds, kwd_mark = (object(),)):
key = args
if kwds:
key += kwd_mark
for item in kwds.items():
key += item
...
return key其中的评论相当具有描述性:
根据位置和关键字参数创建一个缓存键。密钥的构造方式是平面化,尽可能使用,而不是作为一个嵌套结构,占用更多内存。
让我们尝试几个示例运行:
>>> print(make_key((1, 2, 3), dict()))
(1, 2, 3)
>>> print(make_key((1, 2, 3), dict(a='x', b='y')))
(1, 2, 3, <object object at 0x7f6faf99d0c0>, 'a', 'x', 'b', 'y')
>>> print(make_key((1, 2, 4), dict(b='y', a='x')))
(1, 2, 4, <object object at 0x7f6faf99d0c0>, 'b', 'y', 'a', 'x')结果是一个可使用的元组,它表示用户用其user_function调用的参数。正如您已经注意到的,kwd_mark用作args和kwargs之间的一个哨兵值,以便单独缓存以下调用:
user_function(1, 2, 3, 'a', 'x')
user_function(1, 2, 3, a='x')我们可以使用None作为分隔符,但是如果有人用None作为参数调用函数呢?object()是Python中基类的一个对象,虽然它本身并不能做很多事情,但是它的唯一性是有用的。如果您的分隔符是某一类型的,则不能将参数与分隔符混淆!由于这个哨兵是在函数定义时创建的,所以在运行程序时它将保持不变(请注意上面的结果引用相同的<object object at 0x7f6faf99d0c0>),因此它的散列将是相同的。
你可能会问,为什么不让它成为kwd_mark=object()呢?我认为这里的原因是,它只用于将其“附加”到一个元组中,否则每次都必须创建一个新的元组(记住,元组是不可变的):
def make_key(args, kwds, kwd_mark=object()):
key = args
if kwds:
key += (kwd_mark, ) # new tuple
for item in kwds.items():
key += itemhttps://stackoverflow.com/questions/48941388
复制相似问题