首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python lru_cache实现

Python lru_cache实现
EN

Stack Overflow用户
提问于 2018-02-23 04:58:18
回答 1查看 1.3K关注 0票数 5

我试图了解python中lru_cache decorator的实现,特别是它是如何从函数args为其内部dict创建key的。

我一直在读这个https://github.com/python/cpython/blob/master/Lib/functools.py#L414

我无法理解为什么函数中有这个kwd_mark = (object(),)。我看到它只使用一个tuple实例来生成一个object(),它看起来就像一个函数调用的key的所有argskwargs/kwds之间的分隔符。我试着去理解它在这里做什么特别的事情,https://repl.it/repls/ExpensiveFinishedSandboxes,但是我什么都想不出来。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-23 10:43:11

链接是好的,但他们有打破的倾向,所以我会尝试把所有的东西直接包括在答案中。我们有这样一个函数(简化):

代码语言:javascript
复制
def make_key(args, kwds, kwd_mark = (object(),)):
    key = args
    if kwds:
        key += kwd_mark
        for item in kwds.items():
            key += item
    ...
    return key

其中的评论相当具有描述性:

根据位置和关键字参数创建一个缓存键。密钥的构造方式是平面化,尽可能使用,而不是作为一个嵌套结构,占用更多内存。

让我们尝试几个示例运行:

代码语言:javascript
复制
>>> 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之间的一个哨兵值,以便单独缓存以下调用:

代码语言:javascript
复制
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()呢?我认为这里的原因是,它只用于将其“附加”到一个元组中,否则每次都必须创建一个新的元组(记住,元组是不可变的):

代码语言:javascript
复制
def make_key(args, kwds, kwd_mark=object()):
    key = args
    if kwds:
        key += (kwd_mark, )  # new tuple
        for item in kwds.items():
            key += item
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48941388

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档