【问题标题】:Caching attributes with id(self), any better solutions?使用 id(self) 缓存属性,有更好的解决方案吗?
【发布时间】:2015-05-01 15:45:51
【问题描述】:

我正在尝试缓存属性以获得这样的行为:

ply = Player(id0=1)
ply.name = 'Bob'

# Later on, even in a different file
ply = Player(id0=1)
print(ply.name)  # outputs: Bob

所以基本上我想保留不同对象之间的值,只要它们的id0 相等。

这是我的尝试:

class CachedAttr(object):
    _cached_attrs = {}

    def __init__(self, defaultdict_factory=int):
        type(self)._cached_attrs[id(self)] = defaultdict(defaultdict_factory)

    def __get__(self, instance, owner):
        if instance: 
            return type(self)._cached_attrs[id(self)][instance.id0]

    def __set__(self, instance, value):
        type(self)._cached_attrs[id(self)][instance.id0] = value

你会像这样使用这个类:

class Player(game_engine.Player):
    name = CachedAttr(str)
    health = CachedAttr(int)

它似乎工作。然而,我的一个朋友(有点)对此发表了评论:

您正在通过它们的 id(内存地址)存储对象,这很可能会泄漏或从重用指针的新对象中获取垃圾收集对象的值。这很危险,因为 id 本身不是引用,而只是一个独立于对象本身的整数(这意味着您很可能会存储已释放的指针并增大大小,直到遇到 MemoryError)。

我遇到了一些随机崩溃,这可能是崩溃的原因吗? 如果是这样,除了id之外,还有更好的方法来缓存这些值吗?

编辑:只是为了确保;我的Player 类继承自game_engine.Player,这不是我创建的(我只是为其他游戏创建一个mod),并且game_engine.Player 用于始终从他的@ 获取玩家的新实例987654329@。所以这不是我定义的行为。

【问题讨论】:

  • 您想要一个具有相同属性的新对象,还是要检索具有该id 的现有对象? (类似于logging.getLogger 的工作方式。)
  • @chepner 具有相同属性的新对象。
  • id(self) 应该始终是同一个对象的相同值...这表示缓存其值而不是其 id 可能更好...

标签: python caching python-3.x


【解决方案1】:

请查看__new__,而不是__init__。在那里,在 dict 中查找唯一对象并将其返回,而不是创建一个新对象。这样,您就可以避免在需要时对对象进行不必要的分配。此外,您还避免了不同对象具有不同 ID 的问题。

【讨论】:

  • 这是我一开始做的,但是每当原始游戏中的关卡发生变化时,game_engine.Player 类的现有实例(因此我的Player 实例也是如此)不再起作用,不是确定原因,但这就是实际游戏的运作方式。我总是需要在所有游戏之间获取玩家的新实例,因此我只尝试存储属性值,而不是实际实例。
  • 所以有时它应该是相同的,有时不是?这听起来像是一种非常奇怪的做事方式,尤其是将其硬编码到Player 类中。我预见这样你不会让你的代码变得更干净、更易于维护。
猜你喜欢
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
  • 2016-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
  • 2015-02-04
相关资源
最近更新 更多