【问题标题】:How to ignore function arguments with cachetools ttl_cache如何使用 cachetools ttl_cache 忽略函数参数
【发布时间】:2021-12-30 18:21:22
【问题描述】:

我正在利用 cachetools @ttl_cache 装饰器(不是 @cached)。我需要忽略缓存键中的一些参数。例如,。

@ttl_cache(maxsize=1024, ttl=600)
def my_func(foo, ignore_bar, ignore_baz):
    # do stuff

这样工作,我明白了:

>>> my_func("foo", "ignore_bar", "ignore_baz")         # cache miss
>>> my_func("foo", "ignore_bar", "ignore_baz")         # cache hit
>>> my_func("foo", "ignore_bar_bar", "ignore_baz_baz") # cache miss!

我需要什么:

>>> my_func("foo", "ignore_bar", "ignore_baz")         # cache miss
>>> my_func("foo", "ignore_bar", "ignore_baz")         # cache hit
>>> my_func("foo", "ignore_bar_bar", "ignore_baz_baz") # cache hit!!!!!

有没有办法使用@ttl_cache 获得它?

【问题讨论】:

    标签: python python-3.x caching


    【解决方案1】:

    我没有使用过缓存工具,但出于兴趣,我查看了文档。显然,没有内置的方法。如果您真的需要此功能,我可以建议如下 hack:

    class PackedArgs(tuple):
        def __hash__(self):
            return hash(self[0])
    
        def __eq__(self, other):
            if isinstance(other, self.__class__):
                return self[0] == other[0]
            else:
                return NotImplemented
    
    def pack_args(func):
        def inner(packed_args):
            return func(*packed_args)
        return inner
    
    def unpack_args(func):
        def inner(*args):
            return func(PackedArgs(args))
        return inner
    
    @unpack_args
    @ttl_cache(maxsize=1024, ttl=600)
    @pack_args
    def my_func(foo, ignore_bar, ignore_baz):
        # do stuff
    

    本质上:将函数的参数“打包”到一个类似元组的对象中,该对象作为第 0 个元素进行哈希处理,并导致 @ttl_cache 的行为符合您的需要。然后,“解包”它们以恢复正常的界面,并避免在调用时实际上必须传递这一大参数。

    请注意,这只是一个(非常老套的)概念,我根本没有测试过这段代码。它可能不会按原样工作。

    顺便说一句,您的要求听起来很有趣。您可以将其作为功能请求提交给 cachetools 并链接此线程。我可以想象它被实现为类似于 key= kwarg lambda 的东西,类似于内置的 sort's。

    【讨论】:

    • 感谢这个建议。我会试试看,我会让你知道我的评论。
    • 好的,刚试了,没用。从理论上讲,它应该,因为传递给@pack_args 的参数确实具有相同的哈希值。也许@ttl_cache 在幕后以不同的方式行事
    • 我的散列技巧可能只是草率,伙计们here 似乎也覆盖了__eq__。你也可以查看@ttl_cache的源代码,如果你真的需要完成这项工作
    • 谢谢。我真的很欣赏这个解决方法背后的想法。
    • 当然,保留它,如果其他人遇到它,它会使答案自给自足并且更有用
    【解决方案2】:

    嗯,这正是@cached 及其自定义key 参数的用途,所以我想知道您为什么要为此使用@ttl_cache

    from cachetools import TTLCache, cached
    from cachetools.keys import hashkey
    
    def mykey(foo, ignore_bar, ignore_baz):
        return hashkey(foo)
    
    @cached(cache=TTLCache(maxsize=1024, ttl=600), key=mykey)
    def my_func(foo, ignore_bar, ignore_baz):
        # do stuff
    

    【讨论】:

    • 嗨,Thomas,原因是我需要调用 cache_info()cache_clear(),它们不适用于 @cached 装饰器(请参阅 here
    • 我明白了。已经有一个将这些添加到@cached 的功能请求,这可能是要走的路:github.com/tkem/cachetools/issues/131 但是,在这实现之前(恐怕不会很快发生),没有“官方“恐怕要做到这一点。
    • 谢谢托马斯。可以选择使用cache.clear()@cached,而不是cache_clear()@ttl_cache。但是,统计信息将会丢失。
    • 对。 #131 已计划用于 v5.0.0,但由于缺乏资源而被推迟。但是,它肯定会考虑在未来发布,但不要询问发布日期;-)
    • 好的,谢谢。同时,我将使用这个技巧:stackoverflow.com/a/70535619/4820341
    猜你喜欢
    • 2016-04-24
    • 2015-08-24
    • 2021-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多