29 grudnia 2013

[python] Dekoratory

Python ma wbudowany mechanizm pozwalający na implementowanie dekoratorów (wzorzec projektowy), dla istniejących metod. W skrócie, przed wywołaniem pożądanej funkcji wołana jest wcześniej zdefiniowana funkcja dekoratora, której argumentem jest pierwotna funkcja. Dekorator zwraca nową funkcję, która ma być wołana w miejsce pierwotnej.

Poniżej przykład dla funkcji obliczającej rekurencyjnie silnię. Stworzone zostały dwa dekoratory. Pierwszy zajmuje się zapamiętywaniem obliczonych już wartości. Druga metoda drukuje na ekranie parametry wywołania funkcji. Fajny sposób na zapewnienie single responsibility principle.
def cache(fun):
    cache_map = {}
    def _f(*args):
        try:
            if args in cache_map:
                return cache_map[args]
            cache_map[args] = result = fun(*args)
            return result
        except:
            # some element of args can't be a dict key
            return fun(args)
    return _f

def log(fun):
    def _f(*args):
        print('log: ' + fun.__name__ + '(' + str(*args) + ')')
        return fun(*args)
    return _f

@cache
@log
def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n-1)

assert factorial(3) == 6
assert factorial(1) == 1
Wynik:
log: factorial(3)
log: factorial(2)
log: factorial(1)
log: factorial(0)

Brak komentarzy:

Prześlij komentarz