When caching a class will all future instances refer to the exact same id as the original cached instance?

huangapple go评论78阅读模式
英文:

When caching a class will all future instances refer to the exact same id as the original cached instance?

问题

我正在研究类的缓存工作方式,因为我认为这可能是我目前正在处理的代码中的一个问题的合理解决方案。

我一直在使用这个简单的类进行实例创建测试:

from functools import lru_cache

@lru_cache
class Foo:
    def __init__(self, a: int):
        self.a = a
        self.b = sum(i**2 for i in range(self.a))

我看到的情况是,一切都按预期工作,当使用与已缓存的输入相同的输入时,初始化时间为0:

import datetime as dt

start_1 = dt.datetime.now()
bar = Foo(10_000)
elapsed_1 = (dt.datetime.now() - start_1)   # 4008 ms

start_2 = dt.datetime.now()
baz = Foo(5_000)
elapsed_2 = (dt.datetime.now() - start_2)   # 3003 ms

start_3 = dt.datetime.now()
boo = Foo(15_000)
elapsed_3 = (dt.datetime.now() - start_3)   # 5002 ms

start_4 = dt.datetime.now()
bbb = Foo(10_000)
elapsed_4 = (dt.datetime.now() - start_4)   # 0 ms

但在最后一个情况下,我看到没有创建新对象,只是引用了已存在的对象:

id(bar) == id(bbb)   # True

显然,如果我们从类定义中删除 @lru_cache,那么对于 a=10_000 的情况,我们会得到两个不同的对象,而此相同测试(上面的测试)将返回 False。

在缓存类时,新对象总是引用最初缓存的对象的行为是否有保证?

英文:

I was looking at how caching of classes works as I thought it would be a reasonable solution to one of the issues in the code I'm currently working on.

I've been testing the instance creation using this simple class:

from functools import lru_cache

@lru_cache
class Foo:
    def __init__(self, a: int):
        self.a = a
        self.b = sum(i**2 for i in range(self.a))

What I see is that all is working as expected and when using the same input as the one already cached, the initialisation time is 0:

import datetime as dt

start_1 = dt.datetime.now()
bar = Foo(10_000)
elapsed_1 = (dt.datetime.now() - start_1)   # 4008 ms

start_2 = dt.datetime.now()
baz = Foo(5_000)
elapsed_2 = (dt.datetime.now() - start_2)   # 3003 ms

start_3 = dt.datetime.now()
boo = Foo(15_000)
elapsed_3 = (dt.datetime.now() - start_3)   # 5002 ms

start_4 = dt.datetime.now()
bbb = Foo(10_000)
elapsed_4 = (dt.datetime.now() - start_4)   # 0 ms

But in the last case I see that no new object is created, just a new reference to an already existing one:

id(bar) == id(bbb)   # True

Obviously, if we remove @lru_cache from class definition then we get two different objects for the case of a=10_000 and this same test (above) comes back as False.

Is this a guaranteed behaviour when caching classes that the new object will always reference the same originally cached id?

答案1

得分: 3

是的,当你使用functools.lru_cache缓存一个类时,所有将来使用相同输入参数集的该类实例都将引用与原始缓存实例完全相同的对象。

这是因为lru_cache将类的缓存实例存储在一个缓存字典中,以输入参数作为键。当请求使用相同输入参数的类的新实例时,lru_cache会检查缓存字典,以查看是否已存在具有这些输入参数的实例。如果存在,它将返回该实例,否则它将创建一个新实例并将其添加到缓存字典中。

由于缓存字典在类的所有实例之间共享,所有具有相同输入参数的实例将引用内存中相同的对象,即缓存实例。

值得注意的是,这种行为不仅适用于在Python中使用lru_cache缓存类,而且适用于内存中缓存对象的一般行为。如果在内存中缓存一个对象并使用相同的键检索它,你将始终获得内存中完全相同的对象实例。

英文:

Yes, when you cache a class using functools.lru_cache, all future instances of that class with the same set of input arguments will refer to the exact same object as the original cached instance.

This is because lru_cache stores the cached instances of the class in a cache dictionary, with the input arguments as the key. When a new instance of the class is requested with the same input arguments, lru_cache checks the cache dictionary to see if an instance with those input arguments already exists. If it does, it returns that instance, otherwise it creates a new instance and adds it to the cache dictionary.

Since the cache dictionary is shared among all instances of the class, all instances with the same input arguments will reference the same object in memory, which is the cached instance.

It's worth noting that this behavior is not specific to caching classes with lru_cache in Python, but is a general behavior of caching objects in memory. If you cache an object in memory and retrieve it using the same key, you will always get the exact same object instance in memory.

huangapple
  • 本文由 发表于 2023年5月10日 12:27:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76214887.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定