2
7

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 3 years have passed since last update.

Pythonのラッパーとデコレータを使いこなしたい

Last updated at Posted at 2021-09-21

ラッパー

ラッパーには大まかに、以下の3つがある。

  1. 引数を細工して元の関数を呼び出す
  2. 元の関数を呼び出した後、結果に細工をする
  3. 前後に処理を追加する
import inspect

"""
Python ラッパーとデコレータ
"""
# 元の関数
def infected(COVID_19_flg):
    if COVID_19_flg:
        return 'infected'
    else:
        return 'uninfected'
    

# 1.引数を細工して元の関数を呼び出す
def wear_mask(func):
    def wrapper(COVID_19_flg):
        if COVID_19_flg:
            COVID_19_flg = False
        return func(COVID_19_flg)
    return wrapper
    
# 2.元の関数を呼び出した後、結果に細工をする
def passed_2weeks(func):
    def wrapper(COVID_19_flg):
        ret = func(COVID_19_flg)
        if ret == 'infected':
            ret = 'uninfected'
        return ret
    return wrapper

# 3.前後に処理を追加する
def output_log(func):
    def wrapper(*args, **kargs):
        print(f'### START {inspect.currentframe().f_code.co_name} ###')
        ret = func(*args, **kargs)
        print(f'### END {inspect.currentframe().f_code.co_name} ###')
        return ret
    return wrapper
    
COVID_19_flg = True

func_1 = wear_mask(infected)
print(func_1(COVID_19_flg)) # マスクしているのでuninfected

func_2 = passed_2weeks(infected) 
print(func_2(COVID_19_flg)) # 2週間経ったのでuninfected

func_3 = output_log(infected) 
print(func_3(COVID_19_flg)) # STARTとENDのログが出力

    

デコレータ

デコレータはラッパーのコードの最後の部分に記載していた以下のような記述を簡単に行える。

## ~~~~~~~~~~~~~~省略~~~~~~~~~~~~~
func_3 = output_log(infected)
## デコレータを使うと以下のようになる
@output_log
def infected(COVID_19_flg):
    if COVID_19_flg:
        return 'infected'
    else:
        return 'uninfected'

簡単に「hello!」とログを出力するだけのプログラムをデコレータをつかって考えてみると以下のようになる。

def output_log(func):
    def wrapper(*args, **kargs):
        print(f'### START {inspect.currentframe().f_code.co_name} ###')
        ret = func(*args, **kargs)
        print(f'### END {inspect.currentframe().f_code.co_name} ###')
        return ret
    return wrapper

# デコレータ付き関数
@output_log
def print_hello():
    print('hello!')

今回は説明しないが、関数以外の引数を受け取るデコレータを作る場合、今回説明したものに加え、もう1階層上に「関数以外の引数を受け取る専用の高階関数」を作る必要が出てくる。

2
7
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
2
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?