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 默认变量初始化变量会在对象实例化过程中保持状态?
使用带有cythonized类的dask。酸洗对象方法时出错
仅在对象实例的生命周期内保持 Python 解释器处于活动状态