Python酸洗保持对象身份

Posted

技术标签:

【中文标题】Python酸洗保持对象身份【英文标题】:Python pickling keep object identity 【发布时间】:2012-12-07 16:53:15 【问题描述】:

有没有办法保留腌制对象的身份,即有下面的打印True

import pickle

class Foo:
    pass

x = Foo()
print(x is pickle.loads(pickle.dumps(x)))          #False

我在 Linux 机器上使用 cPickle 和 cpython 3.x,不需要可移植的东西。

【问题讨论】:

不,身份是特定实例的身份。 @Cameron,我需要这个,因为我有具有缓存属性的对象,缓存是我存储为对象属性的字典(对象本身作为字典的键)。这一切都很好。但是,当我腌制对象,将其发送到某处,然后取消腌制时,我现在有了一个新对象,其旧对象 ID 保存在缓存字典的键中。这个缓存的属性是一个通用工厂,我不想乱用 __eq__ __ne__ 方法。不确定__getstate____setstate__ 方法是否可行? 我认为是比较对象的内存位置......所以它可能永远不会导致真实...... 当你将对象发送到某个地方时,你是否也发送了缓存? 是的,确切地说,我也发送了缓存 - 尝试使用密钥的 id 进行返工,因为听起来不可能保留身份。 【参考方案1】:

是的,这是可能的;您需要以某种方式在腌制结果中包含“身份”;在这种情况下,最自然的方法是使用 __getnewargs__ 并让 __new__ 方法返回现有的缓存实例。

import uuid
import weakref


class Foo(object):
    ident_cache = weakref.WeakValueDictionary()

    def __new__(cls, identity=None, **kwargs):
        if identity is None:
            identity = uuid.uuid1()
        try:
            self = cls.ident_cache[identity]
        except KeyError:
            self = super(Foo, cls).__new__(cls)
            self.__identity = identity
            self.__init__(**kwargs)
            cls.ident_cache[identity] = self
        return self

    def __getnewargs__(self):
        return (self.__identity,)

    def __init__(self, foo):
        self.foo = foo
>>> import pickle
>>> a = Foo(foo=1)
>>> b = pickle.loads(pickle.dumps(a, pickle.HIGHEST_PROTOCOL))
>>> a is b
True

重要的一点是您必须使用协议版本 2(或更高版本,假设);因为否则,__new__ 永远不会被调用。这只是pickle.dumps 关心的问题,loads 不关心。

【讨论】:

这没有意义。我为什么要在箱子里腌制?持久保存对象基本上意味着我想在进程停止时重建它,然后再次启动(启动程序)。或者我想将酸洗的结果发送到网络中的其他地方。在这种情况下,我几乎无法确保获得相同的唯一标识——至少在最常用的实现中,对象的标识实际上是它所在的地址。 一个有用的例子是当一个对象在从进程“a”传递到进程“b”的pickle中被提及,然后进程“b”将一些信息传递回“a” " 它提到了它从 "a" 获得的对象,在这种情况下,"a" 最好将对象视为它最初创建的对象,而不是一个新的、否则相同的对象。 非常感谢您实际回答了这个问题,而不是问“您为什么要这样做?”回复!这非常有用,即使在两年后 :-)【参考方案2】:
import pickle

class Foo:
    _id_counter = 0
    def __init__(self):
        self._id = Foo._id_counter
        Foo._id_counter += 1

x = Foo()
print(x._id==pickle.loads(pickle.dumps(x))._id)     # True

【讨论】:

如何保存对象身份,这不符合x is pickle.loads(pickle.dumps(x))的要求,这只是保存了一个名为“_id”的属性

以上是关于Python酸洗保持对象身份的主要内容,如果未能解决你的问题,请参考以下文章

Python、cPickle、酸洗 lambda 函数

为啥通过 python 默认变量初始化变量会在对象实例化过程中保持状态?

使用带有cythonized类的dask。酸洗对象方法时出错

仅在对象实例的生命周期内保持 Python 解释器处于活动状态

Pyspark UDF 酸洗错误,无法酸洗 SwigPyObject 对象

使用访问令牌和刷新令牌保持身份验证