1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ラップする関数のシグネチャを維持したラッパーを作成する方法

Last updated at Posted at 2017-07-19

特に関数デコレータでは、引数として受け取った修飾する関数をラップする関数を作成して返すことがよくありますが、ラップする関数のシグネチャをラップされる関数と同じにしたい時があります。
Python 3.4以降では、標準ライブラリfunctoolsが提供するwrapsというデコレータを使ってこの実装が可能です。

以下の例では、デコレータargs_as_intsで修飾後のfunny_function(つまりfunctools.wrapsで修飾後のwrapper)は、修飾される関数funny_functionと同じシグネチャを持ちますが、全ての引数をintに変換して元の関数を同じ計算を行います。

# Source: https://stackoverflow.com/questions/147816/preserving-signatures-of-decorated-functions

import functools

def args_as_ints(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return func(*args, **kwargs)
    return wrapper

@args_as_ints
def funny_function(x, y, z=3):
    """Computes x*y + 2*z"""
    return x*y + 2*z

修飾された後のfunny_functionには、__wrapped__というメンバーがあり、元々の関数が保持されています。

関数のシグネチャを調べるには、標準ライブラリinspectを用います。inspectで提供されているsignature関数を用いると、関数のシグネチャを、Signatureオブジェクトとして取り出すことができます。次のコードでは、funny_functionのシグネチャが、修飾前後で同じであることを確かめています。

>>> from inspect import signature
>>> str(signature(funny_function))
'(x, y, z=3)'
>>> signature(funny_function) == signature(funny_function.__wrapped__)
True
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?