Python functools

functools.wraps を使用すると、デコレータを適用した関数が元の関数のメタデータ(名前やドキュメント文字列など)を保持することができます。使用しない場合、これらのメタデータは失われます。
functools.lru_cache を使用すると、関数の結果をキャッシュすることで計算が高速化されます。使用しない場合、毎回計算が行われるため遅くなります。
functools.partial を使用すると、関数の一部の引数を固定した新しい関数を簡単に作成できます。使用しない場合、毎回関数を再定義する必要があります。
functools.reduce を使用すると、シーケンスを累積して単一の値に減らす処理が簡潔に書けます。使用しない場合、ループを使って手動で累積計算を行う必要があります。

import functools

# functools.wrapsを使うと、デコレーターを使っても関数の情報が失われません。
def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('Something is happening before the function is called.')
        result = func(*args, **kwargs)
        print('Something is happening after the function is called.')
        return result
    return wrapper

@my_decorator
def say_hello(name):
    """
    この関数にはdocstringがあります。
    このdocstringはデコレーターを使うと失われますが、
    functools.wrapsを使うことで失われません。"""
    print(f'Hello {name}')
    
say_hello('Bob')
print(say_hello.__name__)
print(say_hello.__doc__)

Something is happening before the function is called.
Hello Bob
Something is happening after the function is called.
say_hello

    この関数にはdocstringがあります。
    このdocstringはデコレーターを使うと失われますが、
    functools.wrapsを使うことで失われません。



# 使わなかった場合
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print('Something is happening before the function is called.')
        result = func(*args, **kwargs)
        print('Something is happening after the function is called.')
        return result
    return wrapper

@my_decorator
def say_hello(name):
    """この関数にはdocstringがあります。
    このdocstringはデコレーターを使うと失われます。"""
    print(f'Hello {name}')
    
say_hello('Bob')
print(say_hello.__name__)
print(say_hello.__doc__)

Something is happening before the function is called.
Hello Bob
Something is happening after the function is called.
wrapper
None

functools.lru_cache の比較

使用しなかった場合

def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))  # 計算に時間がかかる

使用した場合

import functools

@functools.lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))  # 計算が高速になる

unctools.partial の比較

使用しなかった場合

def power(base, exponent):
    return base ** exponent

def square(base):
    return power(base, 2)

def cube(base):
    return power(base, 3)

print(square(3))  # 9
print(cube(3))    # 27

使用した場合

import functools

def power(base, exponent):
    return base ** exponent

square = functools.partial(power, exponent=2)
cube = functools.partial(power, exponent=3)

print(square(3))  # 9
print(cube(3))    # 27

functools.reduce の比較

使用しなかった場合

numbers = [1, 2, 3, 4, 5]
total_sum = 0
for num in numbers:
    total_sum += num

print(total_sum)  # 15

使用した場合

import functools

numbers = [1, 2, 3, 4, 5]
total_sum = functools.reduce(lambda x, y: x + y, numbers)
print(total_sum)  # 15


この記事が気に入ったらサポートをしてみませんか?