我正在尝试实现一个mixin,该mixin将一些方法添加到实例中,该实例会破坏基类的特定字段名称的名称。
代码看起来像这样
class TimeSeriesObjectRetrieverMixin(object):
"""Time Series Object Retriever Mixin.
Offers reverse related object retrieval methods to mixed in model where the
reverse relation contains time related fields(DateField, DateTimeField).
"""
# TODO: SERIOUS PERFORMANCE BOTTLENECK DUE TO FUNCTION CODE COMPILATION FOR EVERY
# INSTANTIATION. FIX THIS.
def __init__(self, *args, **kwargs):
self._n = {}
for time_series_object_name, time_series_field_name in self.time_series:
time_series_object = getattr(self, time_series_object_name)
time_series_field = time_series_object.model._meta.get_field(time_series_field_name)
# Time series field has to be one of DateField or DateTimeField.
assert(isinstance(time_series_field, DateField) or
isinstance(time_series_field, DateTimeField))
self._add_get_in_last_delta(time_series_object_name,
time_series_field_name)
def time_series(self):
"""
Time Series Property.
You must implement this property in your base class to mix this
mixin into your model.
Example:
time_seires =
[
('reverse_related_object_name', 'created_time'),
('votes', 'time'),
('cash_flow_rate', 'time'),
]
"""
return super(TimeSeriesObjectRetrieverMixin, self).time_series
因此,此mixin将为每个实例化对象添加get_in_last_delta方法。
但这会导致大量开销,因为编译是针对每个对象实例进行的(_add_get_in_last_delta是使用exec和compile实现的)。
有什么好方法可以将运行时生成的实例方法添加到程序的第一个类定义而不是类实例化的类中?
_add_get_in_last_delta():
def _add_method(self, fn):
from types import MethodType
setattr(self, fn, MethodType(self._n[fn], self))
def _add_get_in_last_delta(self,
time_series_object_name,
time_series_field_name):
# Generate a function name.
fn = 'get_{}_in_last_delta'.format(time_series_object_name)
# Generate a name mangled function code.
exec compile((
'from django.utils import timezone\n'
'def {}(self, delta):\n'
' return self.{}.filter({}__gte=(timezone.now()-delta))').
format(fn, time_series_object_name, time_series_field_name),
'<string>', 'exec') in self._n
# Bind the method to the instance.
self._add_method(fn)
ps我正在django中尝试将此类混入我的模型中。
我认为不需要任何编译代码。您在动态定义函数中所做的所有操作都可以通过普通的Python完成。
from django.utils import timezone
from types import MethodType
def _add_get_in_last_delta(self,
time_series_object_name,
time_series_field_name):
# Generate a function name.
fn = 'get_{}_in_last_delta'.format(time_series_object_name)
def dynamic_method(self, delta, obj=time_series_object_name, field=time_series_field_name):
return getattr(self, time_series_object_name).filter(
**{'{}__gte'.format(time_series_field_name): timezone.now()-delta})
# Bind the method to the instance.
setattr(self, fn, MethodType(dynamic_method, self))
该函数仍将为每个实例执行,但是内部函数在第一次导入时仅编译一次。(由于Python闭包的工作方式,对象/字段名称是通过默认的kwargs提供的,但是任何调用结果方法的人都可以安全地忽略它们。)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句