如何实现可变更新时自动更新的可变PickleTypes
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何实现可变更新时自动更新的可变PickleTypes相关的知识,希望对你有一定的参考价值。
SQLAlchemy提供PickleType
并为任何可变类型(如dict)提供mutation tracking。
SQLAlchemy文档提到这是实现可变PickleType
的方法,但它没有说明如何继续它。
注意:我想在PickleType
中存储一个字典。
你是如何实现的?
答案
虽然文档提到了一些例子,但在我看来这还不够,所以我将在这里添加我的实现,可以用来实现一个被pickle并存储在数据库中的可变dict。
使用文档中的MutableDict
示例:
class MutableDict(Mutable, dict):
@classmethod
def coerce(cls, key, value):
if not isinstance(value, MutableDict):
if isinstance(value, dict):
return MutableDict(value)
return Mutable.coerce(key, value)
else:
return value
def __delitem(self, key):
dict.__delitem__(self, key)
self.changed()
def __setitem__(self, key, value):
dict.__setitem__(self, key, value)
self.changed()
def __getstate__(self):
return dict(self)
def __setstate__(self, state):
self.update(self)
现在创建一个要跟踪的列:
class MyModel(Base):
data = Column(MutableDict.as_mutable(PickleType))
我想看一些其他可能更高级或可能使用不同数据结构的示例。 pickle
的通用方法是什么样的?有一个(我想不会,或者SQLAlchemy会有一个)。
另一答案
这是我提出的解决方案。它包装任何类型并检测任何属性集并调用Mutable.changed()。它还包装函数调用并通过在对象之前和之后拍摄对象的快照来检测更改。应该适用于Pickleable类型......
from sqlalchemy.ext.mutable import Mutable
class MutableTypeWrapper(Mutable):
top_attributes = ['_underlying_object',
'_underlying_type',
'_last_state',
'_snapshot_update',
'_snapshot_changed',
'_notify_if_changed',
'changed',
'__getstate__',
'__setstate__',
'coerce']
@classmethod
def coerce(cls, key, value):
if not isinstance(value, MutableTypeWrapper):
try:
return MutableTypeWrapper(value)
except:
return Mutable.coerce(key, value)
else:
return value
def __getstate__(self):
return self._underlying_object
def __setstate__(self, state):
self._underlying_type = type(state)
self._underlying_object = state
def __init__(self, underlying_object, underlying_type=None):
if (underlying_object is None and underlying_type is None):
print('Both underlying object and type are none.')
raise RuntimeError('Unable to create MutableTypeWrapper with no underlying object or type.')
if (underlying_object is not None):
self._underlying_object = underlying_object
else:
self._underlying_object = underlying_type()
if (underlying_type is not None):
self._underlying_type = underlying_type
else:
self._underlying_type = type(underlying_object)
def __getattr__(self, attr):
if (attr in MutableTypeWrapper.top_attributes):
return object.__getattribute__(self, attr)
orig_attr = self._underlying_object.__getattribute__(attr)
if callable(orig_attr):
def hooked(*args, **kwargs):
self._snapshot_update()
result = orig_attr(*args, **kwargs)
self._notify_if_changed()
# prevent underlying from becoming unwrapped
if result == self._underlying_object:
return self
return result
return hooked
else:
return orig_attr
def __setattr__(self, attr, value):
if (attr in MutableTypeWrapper.top_attributes):
object.__setattr__(self, attr, value)
return
self._underlying_object.__setattr__(attr, value)
self.changed()
def _snapshot_update(self):
self._last_state = pickle.dumps(self._underlying_object,
pickle.HIGHEST_PROTOCOL)
def _snapshot_changed(self):
return self._last_state != pickle.dumps(self._underlying_object,
pickle.HIGHEST_PROTOCOL)
def _notify_if_changed(self):
if (self._snapshot_changed()):
self.changed()
然后将它与PickleType一起使用,如下所示:
class TestModel(Base):
__tablename__ = 'testtable'
id = Column(Integer, primary_key=True)
obj = Column(MutableTypeWrapper.as_mutable(PickleType))
这里的缺点是在每次函数调用之前对底层类进行快照,然后在之后比较更改以验证底层对象是否已更改。这将对性能产生重大影响。
另一种确保修改PickleType对象时更新它们的方法是在提交更改之前复制并分配它们。
以上是关于如何实现可变更新时自动更新的可变PickleTypes的主要内容,如果未能解决你的问题,请参考以下文章