4

このようなデコレータをどのように書くのでしょうか。デコレーターを呼び出すときに max_hits の値を指定できるようにしたい (または省略可能)。

たとえば、望ましい用途は次のようになります。

@memoize(max_hits=7)
def a(val):
    print val

また

@memoize
def a(val):
    print val

(最初の例を使用すると、引数が正しくないというエラーが発生します。)

デコレータ:

class memoize:
    """A decorator to cache previosly seen function inputs.

    usage:
        @memoize
        def some_func(..
    """
    def __init__(self, function, max_hits=None):
        self.max_hits = max_hits
        self.function = function
        self.memoized = {}

    def __call__(self, *args, **kwargs):
        key = (args,tuple(kwargs.items()))
        try:
            return self.memoized[key]
        except KeyError:
            self.memoized[key] = self.function(*args,**kwargs)
        return self.memoized[key]
4

2 に答える 2

8

オプションの引数を取り、デコレータ(つまり、最初の引数として関数を受け取る別の呼び出し可能なオブジェクト)を返す関数を作成memoizeする必要があります。この場合、次の2つの構文を使用できます。max_hits

@memoize()
def func(x):
    [...]

@memoize(max_hits=7)
def func(x):
    [...]

だから、おそらく次の線に沿った何か:

def memoize(max_hits=None):
    """Returns a decorator to cache previosly seen function inputs.

    usage:
    @memoize()
    def some_func(..
    """
    class decorator:
        def __init__(self, function):
            self.max_hits = max_hits
            self.function = function
            self.memoized = {}

        def __call__(self, *args, **kwargs):
            key = (args,tuple(kwargs.items()))
            try:
                return self.memoized[key]
            except KeyError:
                self.memoized[key] = self.function(*args,**kwargs)
            return self.memoized[key]

    return decorator

@memoize()これは機能しますが、最初に必要な@memoize構文は機能しないことに注意してください。後者の場合、装飾している関数は最初の引数()として@memoize渡されます。このケースを処理したい場合は、次のように拡張できます。memoizemax_hitsmemoize

def memoize(max_hits=None):
    if callable(max_hits):
        # For sake of readability...
        func = max_hits
        decorator = memoize(max_hits=None)
        return decorator(func)
    [...original implementation follows here...]
于 2011-05-16T13:53:01.593 に答える
4

3.2以降を使用している場合は、自分で作成しないで、from functools import lru_cache代わりに使用してください

括弧のないバージョンをサポートしたい場合は、「間違った」引数を内省するよりも、関数の引数にセンチネル値を使用することをお勧めします。あれは:

class Memoized(object):
    # As per the memoize definition in the question

# Leave out the "*, " in 2.x, since keyword-only arguments are only in 3.x
from functools import partial
_sentinel = object()
def memoize(_f=_sentinel, *, max_hits=None):
    if _f is _sentinel:
        return partial(Memoized, max_hits=max_hits)
    return Memoized(_f, max_hits=max_hits)
于 2011-05-16T15:02:19.903 に答える