如何在运行时生成实例方法并将其添加到类中,但仅将方法编译一次?

六月

我正在尝试实现一个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是使用execcompile实现的)。

有什么好方法可以将运行时生成的实例方法添加到程序的第一个类定义而不是类实例化的类中?


_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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在运行时将jar添加到classPatch以解决已编译的类包导入问题

如何在运行时将模块中的函数添加到类中,同时保留包的层次结构?

有没有一种方法可以在运行时将方法添加到类定义中?

如何在运行时将项目添加到 wpf 中的 Combobox

有什么方法可以在运行时使用Entity Framework Core(代码优先)将旧版本模型实例添加到数据库中吗?

如何在运行时使用C#将项目添加到ComboBox

如何在运行时将数据源添加到Lookup Edit?

如何在运行时将组件添加到JPanel

如何在运行时将容器添加到Kubernetes容器

Unity-如何在运行时将源代码添加到ParentConstraint

如何在运行时将单元格添加到表

如何在运行时将CIFilter添加到视频

如何在运行时将属性添加到JSON(C#)

如何在运行时将项目添加到TStackPanel

使用ConsistentHashmapping时,如何在运行时将actor添加到akka.net中的组或池中?

如何在运行时将文本框添加到 C# 中的 WPF 窗口?

在运行时将if stmt添加到方法时,VerifyException

C#在运行时或使用Mono.Cecil将代码添加到方法中

如何使用QThread在运行时将QWidget添加到布局中?

如何在运行时在Java中创建新添加的类的实例

罗斯林,如何在运行时实例化脚本中的类并调用该类的方法?

如何在运行时在Delphi中创建自定义属性并将其附加到字段

从方法创建另一个类的实例并将其输出添加到地图

Python如何在运行时创建类的方法

在Java中,是否可以在运行时将Serializable接口添加到没有它的类中?

在运行时将注释添加到字段

在运行时将PictureBox添加到窗体

在运行时将片段添加到TabLayout

在运行时将后缀添加到枚举