Remrinのpython攻略日記

python3に入門しました。python3についてあれこれとサンプルコードとか。

高階関数、デコレータ

高階関数...関数を関数に渡したり、戻り値として関数を返したり。
 
関数に機能を追加できたりする。

print(int(3.14))     # 3
print(int("100", 3)) # 9  :3進法の100は10進法の9

def arg_check(func, arg):
    print(arg)
    return func(arg)

print(arg_check(int, 3.14))
# 3.14
# 3

def args_check(func):
    def check(*args):
        print("args:", args)
        return func(*args)
    return check

def adder(a, b):
    return a + b
f = args_check(adder)
print(f(3, 4))
# args: (3, 4)
# 7

print(args_check(int)("100", 3))
# args: ('100', 3)
# 9

関数内の関数は変数と同様に扱える。
 
 
@マークをつけたデコレータを使って同様の動作ができる

def args_check(func):
    def check(*args):
        print("args:", args)
        return func(*args)
    return check

@args_check
def multiple(a, b):
    return a * b
print(multiple(2, 10))
# args: (2, 10)
# 20

 

lru_cacheデコレータ

(Least-recently-used cache decorator)
 
関数の引数と戻り値を記憶し、同じ引数で呼ばれたら関数を実行せずに値を返す。
同じ引数で何度も呼び出す関数だと劇的に速くなる。

counter = 0
def fib1(n):
    global counter
    counter += 1
    if n in [0, 1]:
        return 1
    return fib1(n - 1) + fib1(n - 2)

print(fib1(24))
print(counter, "回の関数呼び出し")
# 75025
# 150049 回の関数呼び出し
    
    
from functools import lru_cache
counter = 0
@lru_cache(maxsize=1024)
def fib2(n):
    global counter
    counter += 1
    if n in [0, 1]:
        return 1
    return fib2(n - 1) + fib2(n - 2)

print(fib2(24))
print(counter, "回の関数呼び出し")
# 75025
# 25 回の関数呼び出し

 
lru_cacheなしだと関数を15万回呼び出していたが、lru_cacheありだと25回で済む。

参考:
10.2. functools — 高階関数と呼び出し可能オブジェクトの操作 — Python 3.6.1 ドキュメント