ランダムに何か値を返す時に その関数の返し値がuniqueになってほしいことがあります. 実際には ほぼ 同じ値にならなかったりするので その対処はしなかったりします.

そこで 関数が同じ値を返したら計算し直すデコレータを書いてみました. 内部的に辞書を使っている都合上, 引数のそれぞれの型はhashableである必要があります.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from collections import defaultdict
from functools import wraps
from inspect import signature


def unique(f):
    f.unique_cache = defaultdict(set)

    @wraps(f)
    def _unique(*args, **kw):
        result = f(*args, **kw)
        key = _normal_arguments(f, *args, **kw)

        if result in f.unique_cache[key]:
            return _unique(*args, **kw)

        f.unique_cache[key].add(result)
        return result

    return _unique


def _normal_arguments(f, *args, **kw):
    sig = signature(f)
    b = sig.bind(*args, **kw)
    b.apply_defaults()
    values = tuple(b.arguments.values())
    return values

使い方

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from random import choice
from string import ascii_letters

from unique import unique


@unique
def random_str(size):
    return ''.join([choice(ascii_letters) for _ in range(size)])