
Python functools について
目次
概要
前回は decorator について説明しました。
本記事では Python デコレータで見かける functools について紹介します。
functoolsとは
関数系のモジュールです。関数を加工したり、特定の属性を別の関数に移行する時に使用します。
なぜ必要?
よく見かけるけど、なぜ必要? と思うかもしれません。
実はそのままデコレータを使うと、デコレートされる関数の doc 等が参照できなくなるからです。
mkdocs, sphinx 等は関数の docstring を参照してサイト等を作成しますが、デコレータを使用すると、デコレートされた関数のもではなく、新規で作成した関数の属性を参照します。
docstring 等を保持したい場合、何かしら継承する関数が必要になります。
functools の wrap系 を使えば、デコレートされる関数の name や docstring を維持することができます。
代表的な関数の紹介
上記では一例をもとに functools の必要性について紹介しました。本記事では、代表的な関数をいくつか紹介します。
partial
一部の引数に対して値を埋め込んだ状態で新たに関数を作成する関数です。
import functools
def hoge(name, age):
return {"name": name, "age": age}
partial_name = functools.partial(hoge, "abe")
partial_age = functools.partial(hoge, age=30)
partial_both = functools.partial(hoge, "catty", 32)
partial の第 2 引数移行に変数を指定すれば、対応する引数に値を埋め込みます。 なければ、左から順に値が埋め込まれます。
実行すると以下の通りです。
>> partial_name(30)
{'name': 'abe', 'age': 30}
>> partial_age("beta")
{'name': 'beta', 'age': 30}
>> partial_both()s
{'name': 'catty', 'age': 32}
update_wrapper
属性をコピーする関数です。関数の属性として、docs や name 等がありますが、これらを継承するものです。
import functools
def hoge():
"""hoge doc"""
pass
def fuga():
"""fuga doc"""
pass
functools.update_wrapper(hoge, fuga)
実行すると以下の通りです。
>> hoge.__name__
'fuga'
>> hoge.__doc__
'fuga doc'
また、一部の属性だけを継承したい場合は第3引数に属性を入力することで、指定の属性を継承することができます。
wrap
update_wrapper をデコレータで表現したものです。
import functools
def decorator(func):
@functools.wraps(func)
def rewrite_func(idx):
idx = int(idx)
num = func(idx)
return f"This idx is {num}th(st/nd) element"
return rewrite_func
@decorator
def increase(a):
"""increase doc"""
return a + 1
rewrite_func に対して、func の属性を継承します。
>> increase.__name__
'increase'
>> increase.__doc__
'increase doc'
functools wraps 抜きだと、以下のようになります
>> increase.__name__
'rewrite_func'
>> increase.__doc__
''
ちなみに以下は等価です。 wraps 版
@functools.wraps(func_1)
def func_2():
...
update_wrapper 版
update_wrapper(func_2, func_1)
まとめ
今回デコレータで よく出てくる functools について紹介しました。
また、代表的な関数もいくつか紹介しました。
今後も参考にしていただければと思います。