我有一堆MongoEngine模型的实例。分析器显示在MongoEngine模型字段的__get__
方法中花费了大量时间:
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.066 0.066 26.525 26.525 entity.py:60(list)
2198 0.277 0.000 25.260 0.011 ***.py:96(***)
45603 0.822 0.000 24.832 0.001 ***.py:105(***)
285055 2.732 0.000 21.417 0.000 fields.py:189(__get__)
444491 2.643 0.000 17.476 0.000 dereference.py:12(__call__)
由于这些模型实例是只读的,我想让它们使用简单的Python数据类型。但我无法替换属性:
> .../course_cache.py(339)_patch_me_model_instance()
338 import ipdb; ipdb.set_trace()
--> 339 return obj
340
{1890: 0.6, 1891: 0.4, 1892: 0.6, 1893: 0.4, 1894: 0.2, 1895: 0.8}
ipdb> pinfo obj.tasks
Type: BaseDict
String form: {1890: 0.6, 1891: 0.4, 1892: 0.6, 1893: 0.4, 1894: 0.2, 1895: 0.8}
Namespace: Locals
Length: 6
File: .../local/lib/python2.7/site-packages/mongoengine/base/datastructures.py
Docstring:
A special dict so we can watch any changes
ipdb> obj.__dict__['tasks'] = dict(obj.tasks)
ipdb> pinfo obj.tasks
Type: BaseDict
String form: {1890: 0.6, 1891: 0.4, 1892: 0.6, 1893: 0.4, 1894: 0.2, 1895: 0.8}
Namespace: Locals
Length: 6
File: .../local/lib/python2.7/site-packages/mongoengine/base/datastructures.py
Docstring:
A special dict so we can watch any changes
docs:
中对此进行了描述如果实例的字典具有与数据同名的条目 描述符,数据描述符优先。
但是有没有办法覆盖数据描述符属性的优先级而不修补模型(删除描述符或添加__getattribute__
)?
答案 0 :(得分:1)
这是我的解决方案似乎有效:
def _mock_me_instance(self, obj):
"""Patch a MongoEngine model instance to not use descriptors
to access field values.
"""
# copy class
Model = type(obj.__class__.__name__, obj.__class__.__bases__,
dict(obj.__class__.__dict__))
# add the original model to the base classes, so that isinstance() can work
Model.__bases__ = (self.__class__,) + Model.__bases__
# replace descriptor so that values from __dict__ can be seen
for field_name in obj._fields:
setattr(Model, field_name, None)
obj.__dict__.update(obj.__dict__['_data'])
obj.__class__ = Model # replace the class
return obj
工作原理
isinstance
和issubclass
可以正常工作。__dict__
中。这些值暂时被忽略,因为我们有相同名称的数据描述符,它们会覆盖对数据的访问。None
分配给类中的描述符(在我的例子中是MongoEngine模型字段)。 None
不是描述符,因此现在可以看到来自对象的__dict__
的值。速度增益约为600%(17秒,现在为3)。