装饰重新使用另一个装饰器的实现

时间:2012-12-30 14:35:44

标签: python decorator partial code-reuse

我已经实现了一个memoize装饰器,它允许缓存一个函数。缓存键包括函数参数。类似地,cached装饰器缓存一个函数,但忽略了参数。这是代码:

class ApplicationCache (Memcached):

make_key方法: UltraJSON 快速传递一个字符串,其中 SHA512 哈希成为一个清晰的十六进制摘要:

    def make_key (self, *args, **kwargs):

        kwargs.update (dict (enumerate (args)))
        string = ujson.encode (sorted (kwargs.items ()))
        hashed = hashlib.sha512 (string)

        return hashed.hexdigest ()

memoize装饰器:因为Python 2.x糟透了w.r.t.完全限定的函数名称,我只是强迫用户提供合理的name

    def memoize (self, name, timeout=None):
        assert name

        def decorator (fn):
            @functools.wraps (fn)
            def decorated (*args, **kwargs):

                key = self.make_key (name, *args, **kwargs)
                cached = self.get (key)

                if cached is None:
                    cached = fn (*args, **kwargs)
                    self.set (key, cached, timeout=timeout)

                return cached
            return decorated
        return decorator

cached装饰器:它几乎是memoize的逐字副本,只有make_key忽略参数的唯一例外:

    def cached (self, name, timeout=None):
        assert name

        def decorator (fn):
            @functools.wraps (fn)
            def decorated (*args, **kwargs):

                key = self.make_key (name) ## no args!
                cached = self.get (key)

                if cached is None:
                    cached = fn (*args, **kwargs)
                    self.set (key, cached, timeout=timeout)

                return cached
            return decorated
        return decorator

现在,我对cached的问题是,它为重新分解而尖叫:它应该使用memoize,其目的是消除fn的参数(使用{{ 1}}也许?),如:

functools.partial

我实际上不确定我是否在这里过度使用DRY原则,如果重用是可能的,因为 def cached (self, name, timeout=None): ## Reuse the more general `memoize` to cache a function, ## but only based on its name (ignoring the arguments) 的当前实现忽略了的参数键(但在调用修饰函数时显然)。

1 个答案:

答案 0 :(得分:1)

我将摆脱name参数并提供关键函数作为参数:

def memoize(self, timeout=None, keyfunc=self.make_key):
    ...
    key = keyfunc(function.__name__, *args, **kwargs)
    ...

cache将成为:

def cache(self, timeout=None):
    return self.memoize(timeout, keyfunc=lambda f, *args, **kwargs: f.__name__)