【Python】デコレーターとは?関数デコレーターを実装して説明する

python
あい
あい

今回は関数デコレーターを
実装してデコレーターに
ついて説明していきます

[PR]※本サイトにはプロモーションが含まれています

関数デコレーターとは?

メイン処理(関数)をデコレート(装飾)する機能です

デコレーターを使用すると

メイン処理の関数の中身を変えずに

「@ デコレーター名」と1行追加するだけで

デコレートすることができます

具体例として

以下コードを実行し説明します

import datetime


def print_datetime(f):

    # print_datetime内でwrapper関数が定義されている
    def wrapper():
      print(f"start: {datetime.datetime.now()}")
      f()
      print(f"end: {datetime.datetime.now()}")
    
    # wrapper関数をオブジェクトとして返す
    return wrapper


@print_datetime
def print_greeting():
    s = input("あなたのお名前は? : ")
    print(f"こんにちわ {s} さん")

print_greeting()

実行結果は

メインの処理は名前と

挨拶をする処理です

実行結果を確認すると

実行前と後の時刻が記録が

挿入されていることが確認できました

これがデコレーションです

デコレーターは関数を利用して実装されます

デコレーターのアルゴリズムを

理解するためには

pythonの関数の特性を

理解することが必要です

関数の特性について説明しながら

最終的にデコレーターを実装していきます

関数は引数に関数オブジェクトを渡すことができる

Pythonでは関数の引数に

関数オブジェクトを渡すことで

他の関数で別の関数を利用することができます

以下のコードで説明します

def call_greeting(f):
    f()


# 名前を入力し挨拶される関数
def print_greeting():
    s = input("あなたのお名前は? : ")
    print(f"こんにちわ {s} さん")


call_greeting(print_greeting)

1.call_greeting関数の引数fに

print_greeting関数オブジェクトを渡し

call_greeting関数を呼び出す

2.f()でprint_greeting関数を実行

実行すると

といった実行結果が出てきます。

関数内関数

Pythonは関数内に関数を定義

オブジェクトとして返すことができます

以下コードで説明をします

import datetime


def print_datetime():
    
    # print_datetime内でwrapper関数が定義されている
    def wrapper():
      print(f"start: {datetime.datetime.now()}")
      print("こんにちわ")
      print(f"end: {datetime.datetime.now()}")
    
    # wrapper関数をオブジェクトとして返す
    return wrapper

# wrapperオブジェクトをfuncに格納する
func = print_datetime()

func()

上記のコードは

print_datetime関数内に

wrapper関数を定義し

wrapper関数をオブジェクトとして

funcに返し

func()でwrapperを実行する

コードになります

funcはオブジェクトなので

func()を行うことでwrapperの実行結果を

出力することが可能になります

実行すると

といった結果が得られました

関数でデコレーター機能を実装する

Pythonでは関数の引数に

関数オブジェクトを渡すことで

他の関数で別の関数を利用することができる

Pythonは関数内に関数を定義し

オブジェクトとして返すことがで

この二つの性質を利用して

デコレーターを実装していきます

import datetime


def print_datetime(f):

    # print_datetime内でwrapper関数が定義されている
    def wrapper():
      print(f"start: {datetime.datetime.now()}")
      f()
      print(f"end: {datetime.datetime.now()}")
    
    # wrapper関数をオブジェクトとして返す
    return wrapper

# 名前を入力し挨拶される関数
def print_greeting():
    s = input("あなたのお名前は? : ")
    print(f"こんにちわ {s} さん")

# wrapperオブジェクトをfuncに格納する
func = print_datetime(print_greeting)

func()

処理の順番として

1.print_datetime関数の引数fに

print_greeting関数オブジェクトを渡し

print_datetime関数を呼び出す

2.wrapper関数をprint_datetime関数内で定義

3.wrapper関数をオブジェクトとして返しfuncに格納

4.func()でwrapper関数を実行

出力結果は

メインの名前の入力と挨拶の

処理の間に処理を行った時間が

デコレートされています

デコレーターを実装する

「@ デコレーター名」を追加して

上記のコードを書き替えます

import datetime


def print_datetime(f):

    # print_datetime内でwrapper関数が定義されている
    def wrapper():
      print(f"start: {datetime.datetime.now()}")
      f()
      print(f"end: {datetime.datetime.now()}")
    
    # wrapper関数をオブジェクトとして返す
    return wrapper


@print_datetime
def print_greeting():
    s = input("あなたのお名前は? : ")
    print(f"こんにちわ {s} さん")

print_greeting()

完成しました

print_greetingは

print_datetimeでデコレーション

されたことになりました

出力結果は以下のようになります

あい
あい

デコレーターは
メインの処理を
変えずに

様々な機能を
装飾していく
イメージなんだね!

タイトルとURLをコピーしました