猿问

Python mixin/decorator/__metaclass__ 用于基类增强

我正在为 Django REST API 实现一个内容感知缓存系统。我想开发一个可以添加到现有视图的组件,该组件将通过检查缓存并在未命中时回退到基类行为来修改基类的行为。


基本上,我有这样的事情:


class Base:

   def get(self, request, *args, **kwargs):

       ....

       return Response


class AnotherBase:

   def get(self, request, *args, **kwargs):

       .... 

       return Response


class Derived(Base):

    pass


class OtherDerived(AnotherBase):

    pass

我最初的想法是做一些类似的事情


class Cacheable:

    def get(self, request, *args, **kwargs):

       cache_key = self.get_cache_key(request)

       base_get = #.... and this is the problem

       return cache.get(cache_key, base_get(request, *args, **kwargs))


    def get_cache_key(self, request):

       # .... do stuff


class Derived(Cacheable, Base):

    pass


class AnotherDerived(Cacheable, AnotherBase):

    pass

很明显这不起作用,因为我不知道如何,或者是否可能,或者是否建议从 mixin 访问兄弟超类。


我的目标是一种实现,它允许我在不触及现有类的内部结构的情况下向现有视图添加缓存行为。给定一个视图类, C, st C.get(request, *args, **kwargs) -> Response,是否有一个函数, F, stF(C).get(...在回退到 之前是否进行缓存检查C.get?在这个准正式的表示法中,我们会说向类定义中最左边的父类添加一个 mixin 算作一个函数。


使用方法装饰器是否更合适?或者类装饰器如何工作?


然后我__metaclass__在研究这个时看到了参考资料,但我不清楚这种方法是什么样的。


这是 Python 3.6


回首忆惘然
浏览 111回答 3
3回答

慕雪6442864

简单的例子:def Base:    def _get_data(self):        # get the data eg from database        return self._get_data_native()    def get(self, request, *args, **kwargs):        return Response(self._get_data())def Cacheable(Base):    def _get_data(self):        # get from cache ...        result = ...        if result is None:            # or from base ...            result = ...        return resultdef Derived(Cacheable):    def _get_data_native(self):        # get the data eg from database        ...通过从 Cacheable 继承,您可以在此处包含缓存,因为在此处_get_data被覆盖。对于这个问题,如果您只想在一个地方添加缓存,则不需要元类或装饰器。当然,装饰器可用于以更通用的方式包含缓存。

慕村225694

答案是一个装饰器和一些Django特定的库。from django.utils.decorators import method_decoratorfrom django.core.cache import cachedef cached_get(cache_key_func=None):    """    Decorator to be applied via django.utils.decorators.method_decorator    Implements content-aware cache fetching by decorating the "get" method    on a django View    :param cache_key_func: a function of fn(request, *args, **kwargs) --> String    which determines the cache key for the request    """    def decorator(func):        def cached_func(request, *args, **kwargs):            assert cache_key_func is not None, "cache_key_function is required"            key = cache_key_func(request, *args, **kwargs)            result = cache.get(key)            if result is None:                return func(request, *args, **kwargs)            return Response(result)        return cached_func    return decorator@method_decorator(cached_get(cache_key_func=get_cache_key), name="get")class SomeView(BaseView):    ...def get_cache_key(request):    # do arbitrary processing on request, the following is the naïve melody    key =  urllib.urlencode(request.query_params)    return key 因此,解决方案是使用 Django 的内置method_decorator函数,将其第一个参数装饰器应用于装饰类的方法,该方法由第二个参数name, to命名method_decorator。我定义了一个高阶函数,cached_get,它接受另一个函数作为它的参数,并返回一个柯里化函数(闭包,所谓的)。通过调用这个函数get_cache_key(而不是,请注意,调用该函数),我有一个装饰器,它将应用于 .get 方法SomeView。装饰器本身是一个简单的 Python 装饰器——在这个应用程序中,它是cached_func,而原始的、未装饰的get方法是func。因此,cached_func内容替换SomeView.get,所以当SomeView.get被调用时,它首先检查缓存,但回落到未命中未修饰方法。我希望这种方法能够在通用适用性与内容感知密钥派生之间取得平衡。

潇湘沐

我的两分钱:你正在走进这里晦涩难懂的领域。熟悉所有相关概念,尝试一些,然后再决定。这是一个关于元类的很好的教程。这里有一个关于装饰器。我绝不隶属于该网站。
随时随地看视频慕课网APP

相关分类

Python
我要回答