ホーム >  Python >  Pythonのデコレーターで関数を修飾してみよう その2 デコレータの条件

投稿日:   |  最終更新日:

Pythonのデコレーターで関数を修飾してみよう その2 デコレータの条件

Python

Pythonのデコレーター機能の研究第2弾です。

デコレーターとは、関数を受け取って戻すもの

前回、デコレータとは関数のラッパーと紹介しました。ラッパーを先に定義することにより、複数の関数に共通の処理を持たせます。しかし、これでは定義がいまいちよくわからないのでもう少し踏み込んでみます。

class MyClass:
    # …… 省略 ……

    @classmethod  # クラスメソッドであることを示すデコレーター
    def get_count(cls):  # デコレーターで修飾されたメソッド(関数)
        print(cls.count)

デコレーターを使うだけなら、上記のように「@デコレーター」(デコレーター式)を使って関数を修飾(デコレート)するだけでOKです。

デコレータは、基本的には関数を受け取り、関数を戻り値とする関数です(そうではない場合もあります)。また、クラスを受け取り、クラスを戻り値とする関数やクラスも書くことができます。

デコレーターの条件

Pythonにおけるデコレーターの条件は以下の通りです。

  • 関数を受け取り、関数を戻り値とする関数
  • デコレーターを使うには、関数定義(やクラス定義)の前に「@デコレーター」を付ける
  • デコレーターは、受け取った関数に何らかの処理を施して、それを戻り値とする

環境

Python 3.6.5

基本的なデコレーターの定義

まずはデコレーター式を使わずに、そのままデコレーターを実行してみます。

#デコレーター
def mydecorator(func):
    def inner_func(*args):
        print(f'before execute {func.__name__}')
        result = func(*args)
        print(f'after execute {func.__name__}')
        return result
    return inner_func

#実行部分
mylen = mydecorator(len)  # 組み込みのlen関数をmydecorator関数に渡す
print(mylen('string'))

実行結果

before execute len
after execute len
6

解説

#デコレーター
def mydecorator(func):
    def inner_func(*args):
        print(f'before execute {func.__name__}')
        result = func(*args)
        print(f'after execute {func.__name__}')
        return result
    return inner_func

mydecorator関数はパラメーターfuncに関数を受け取ります。そして、内部で定義しているinner_func関数が戻り値です。つまり、この関数はデコレーターとして使用できます。

#デコレーター
def mydecorator(func):
    def inner_func(*args): #①
        print(f'before execute {func.__name__}') #③
        result = func(*args) #②
        print(f'after execute {func.__name__}') #③
        return result
    return inner_func

①パラメーター「*args」に任意の数の値を受け取ります。

②「result = func(*args)」という行で、自らのパラメーター「*args」に受け取った値を引数として、mydecorator関数がパラメーターfuncに受け取った関数を呼び出しています。

③その前後では、メッセージを表示します。

「func.__name__」というのは、パラメーターfuncに受け取った関数の名前を表しています。

 

#実行部分
mylen = mydecorator(len) 

変数mylenにlen関数を内部で実行する関数が代入されます。

print(mylen('string'))

実際にその関数を呼び出します。「mylen(‘string’)」は意味的には「inner_func(‘string’)」となります。(このとき、inner_func関数では、そのローカル変数funcに組み込みのlen関数が代入されています。)


独自の関数にデコレーターを適用

今度はmydecorator関数を適用する関数も作ります。

#デコレーター
def mydecorator(func):
    def inner_func(*args):
        print(f'before execute {func.__name__}')
        result = func(*args)
        print(f'after execute {func.__name__}')
        return result
    return inner_func

#実行部分
def myfunc(msg):
    print(msg)

myfunc = mydecorator(myfunc)
myfunc('hello world')

実行結果

before execute len
hello world
after execute len

@デコレーターを使う場合

「@デコレーター」を使うと、以下のように書けます。

#デコレーター
def mydecorator(func):
    def inner_func(*args):
        print(f'before execute {func.__name__}')
        result = func(*args)
        print(f'after execute {func.__name__}')
        return result
    return inner_func

#実行部分
@mydecorator
def myfunc(msg):
    print(msg)

myfunc('hello world')

実行結果

before execute len
hello world
after execute len



トラックバック用のURL
プロフィール

名前:イワサキ ユウタ 職業:システムエンジニア、ウェブマスター、フロントエンドエンジニア 誕生:1986年生まれ 出身:静岡県 特技:ウッドベース 略歴 20

最近の投稿
人気記事
カテゴリー
広告