首页 > 解决方案 > 如何在 __new__ 方法中使用 pickle 缓存对象?

问题描述

我想在__new__方法中缓存一个对象,以便在构造新对象时可以加载缓存,但是现在以下代码将出现异常:

RecursionError: maximum recursion depth exceeded while calling a Python object

我不知道如何打破递归

import pickle

class Cache:
    def __init__(self):
        self.d = {}

    def __setitem__(self, obj, val):
        self.d[obj] = pickle.dumps(val)

    def __getitem__(self, obj):
        return pickle.loads(self.d[obj])

class Car:

    cache = Cache()

    def __reduce__(self):
        return (self.__class__, (self.name,))

    def __new__(cls, name):
        try:
            return cls.cache[name]
        except KeyError:
            return cls.new(name)

    @classmethod
    def new(cls, name):
        car = object.__new__(cls)
        car.init(name)
        cls.cache[name] = car
        return car

    def init(self, name):
        self.name = name

    def __repr__(self):
        return self.name


a = Car('audi')
b = Car('audi')

标签: pythonpython-3.xcachingpickle

解决方案


试试。这可能会解决这个问题,但它可能不是正确的解决方案。如果有人有更好的想法,请随时发表评论。

只需删除该__reduce__方法。

然后实施__getnewargs____getnewargs_ex__

import pickle

class Cache:
  def __init__(self):
    self.d = {}

  def __setitem__(self, obj, val):
    self.d[obj] = pickle.dumps(val)

  def __getitem__(self, obj):
    return pickle.loads(self.d[obj])

  def __contains__(self, x):
    return x in self.d

class Car:
  cache = Cache()

  def __new__(cls, name, extra=None, _FORCE_CREATE=False):
    if _FORCE_CREATE or name not in cls.cache:
      car = object.__new__(cls)
      car.init(name)
      car.extra = extra
      cls.cache[name] = car
      return car
    else:
      return cls.cache[name]

  def init(self, name):
    self.name = name

  def __repr__(self):
    return self.name

  def __getnewargs__(self):
    return (self.name, None, True)

  def __getnewargs_ex__(self):
    # override __getnewargs_ex__ and __getnewargs__ to provide args for __new__
    return (self.name, ), {"_FORCE_CREATE": True}

a = Car('audi', extra="extra_attr")
b = Car('audi')

print(id(a), a.extra) # 1921399938016 extra_attr
print(id(b), b.extra) # 1921399937728 extra_attr

推荐阅读