无法腌制记忆化类实例

2024-05-11 08:09:00 发布

您现在位置:Python中文网/ 问答频道 /正文

这是我使用的代码

import funcy

@funcy.memoize
class mystery(object):

    def __init__(self, num):
        self.num = num

feat = mystery(1)

with open('num.pickle', 'wb') as f:
    pickle.dump(feat,f)

这给了我以下错误:

^{pr2}$

我希望1)理解为什么会发生这种情况,2)找到一个解决方案,让我可以对对象进行pickle处理(不删除记忆)。理想情况下,解决方案不会将调用更改为pickle。在

运行functy==1.10的python3.6


Tags: 代码importselfobjectinitdef情况解决方案
2条回答

另一种方法是

class _mystery(object):

    def __init__(self, num):
        self.num = num

@funcy.memoize
def mystery(num):
    return _mystery(num)

问题是您已经将为函数设计的decorator应用到类中。结果不是一个类,而是一个结束对类的调用的函数。这会导致很多问题(例如,正如aranfey在评论中指出的,你不能isinstance(feat, mystery),因为mystery)。在

但您关心的特别问题是不能pickle不可访问类的实例。在

实际上,这基本上就是错误消息告诉你的:

PicklingError: Can't pickle <class '__main__.mystery'>: it's not the 
same object as __main__.mystery

你的feat认为它的类型是__main__.mystery,但那根本不是一个类型,而是由修饰符返回的函数包装了该类型。在


解决这个问题的简单方法是找到一个类decorator,它可以满足您的需要。它可能被称为flyweight而不是memoize,但我相信有很多例子存在。在


但是,您可以通过记住构造函数而不是记住类来构建flyweight类:

^{pr2}$

…虽然在这种情况下,您可能希望将初始化移到构造函数中。否则,调用mystery(1),然后调用mystery(1)将返回与之前相同的对象,但也会使用self.num = 1重新初始化它,这充其量是浪费,最坏的情况是不正确的。所以:

class mystery:
    @funcy.memoize
    def __new__(cls, num):
        self = super().__new__(cls)
        self.num = num
        return self

现在:

>>> feat = mystery(1)
>>> feat
<__main__.mystery at 0x10eeb1278>
>>> mystery(2)
<__main__.mystery at 0x10eeb2c18>
>>> mystery(1)
<__main__.mystery at 0x10eeb1278>

而且,由于feat的类型现在是一个可以在模块全局名称mystery下访问的类,pickle将不会有任何问题:

>>> pickle.dumps(feat)
b'\x80\x03c__main__\nmystery\nq\x00)\x81q\x01}q\x02X\x03\x00\x00\x00numq\x03K\x01sb.'

你还想想想这门课应该怎么学酸洗。特别是,您是否希望unpickling遍历缓存?默认情况下,它不会:

>>> pickle.loads(pickle.dumps(feat)) is feat
False

{这只相当于使用默认值的^来做什么

result = object.__new__(__main__.mystery)
result.__dict__.update({'num': 1})

如果您希望它通过缓存,最简单的解决方案是:

^{8}$

如果您打算经常这样做,您可能会考虑编写自己的类装饰器:

def memoclass(cls):
    @funcy.memoize
    def __new__(cls, *args, **kwargs):
        return super(cls, cls).__new__(cls)
    cls.__new__ = __new__
    return cls

但是这个:

  • …有点难看
  • …只适用于不需要向基类传递构造函数参数的类
  • …仅适用于没有__init__(或者至少,具有幂等且快速的__init__的类,重复调用是无害的)
  • …不能提供一种简单的方法来钩住酸洗,并且
  • …没有记录或测试这些限制。在

所以,我认为你最好是明确地记住__new__方法,或者编写(或找到)一些更为精巧的东西,来进行必要的内省,从而使以这种方式记类变得完全通用。(或者,也可以编写一个只适用于某些受限类集的程序,例如,@memodataclass@dataclass类似,但是使用一个记忆化的构造函数要比完全通用的@memoclass简单得多。)

相关问题 更多 >