Python 上級チュートリアル シリーズ: Python クロージャとデコレータ

今日もPythonのクロージャとデコレータについて解説していきます。これら 2 つの概念についてはまだ詳しく学習していませんが、オブジェクト指向プログラミングではすでにデコレータを頻繁に使用しています。デコレータは、糖衣構文と同じくらい便利な機能を関数に追加できます。Python では、デコレータの形式は通常、関数の上に @ 記号を追加します。

この章の学習目標を見てください。

  • クロージャの構成条件を知ることができる

  • クロージャを定義するための基本的な構文を知る能力

  • クロージャで使用される外部変数を変更するために必要なキーワードを知ることができる

  • デコレータを定義するための基本的な構文と機能を理解できる

  • 汎用デコレータを作成する機能

  • 複数のデコレータを使用して関数を装飾する機能

  • パラメータを取るデコレータを作成する機能

  • クラスデコレータの使用法を理解する能力

閉鎖

以下にクロージャの概念を紹介します。その前に、変数がどのようにメモリに格納されるかを説明する必要があります。前に述べたように、Python コードの変数は、グローバル変数とローカル変数の 2 つのタイプに分類されます。クロージャはローカル変数に関するものです。次に、クロージャについて詳しく説明します。

変数がメモリに格納される仕組み

序文: グローバル変数とローカル変数へのアクセス

グローバル変数のアクセス範囲:

①グローバル変数はグローバルスコープで正常にアクセス可能

②ローカルスコープでもグローバル変数に正常にアクセス可能

ローカル変数のアクセス範囲:

①ローカル変数はローカルスコープ内で正常にアクセス可能

② 関数実行後は内部変数が消滅してしまうため、グローバルスコープではローカル変数に正常にアクセスできません。コードでは次のように示されます。

 
 
 
 

「」
スコープは変数のスコープであり、使用できる場所と使用できない場所を示します。
関数の出現により、Python の変数は 2 種類のスコープに分けられます。 ① グローバル スコープ ② ローカル スコープ スコープの
出現により、変数も 2 種類に分けられます。 ① グローバル変数 ② ローカル変数
① グローバル変数: グローバルスコープで定義された変数はグローバル変数です。
② ローカル変数: ローカルスコープで定義された変数はローカル変数です
''
# グローバルスコープ
num1 = 10 # グローバル変数
def func():
# ローカルスコープ
num2 = 100 # ローカル変数

拡張機能: 関数の実行後に内部変数が消えるのはなぜですか? 答え: メモリのガベージ コレクション メカニズム

1. クロージャの役割

以前に関数について学習しました。関数が呼び出されると、関数内で定義された変数が破棄されることはわかっていますが、場合によっては、この変数を関数内に保存し、毎回この変数に基づいて一連の操作を完了する必要があることがあります。例: この変数に基づいて他の数値との合計が計算されるたびに、どうすればよいでしょうか? 

この要件は、今日学んだクロージャによって解決できます。 

クロージャの定義: 

関数のネストを前提として、内部関数は外部関数の変数を使用し、外部関数は内部関数のアドレスを返しますが、この外部関数の変数を使用する内部関数をクロージャと呼びます。

2. 閉鎖条件

クロージャの定義を通じて、クロージャの形成条件を知ることができます。 

①関数のネスティングを前提(関数の中に関数を定義) 

②内部関数は外部関数の変数を使用します(外部関数のパラメータも含みます) 

③ 外部関数が内部関数を返す

3. クロージャのサンプルコード

 
 
 
 

# 外部関数を定義します
def func_out(num1):
# 内部関数を定義します
def func_inner(num2):
# 内部関数は外部関数の変数を使用します (num1)
result = num1 + num2
print("結果は:", result)
# 外部関数は内部関数を返し、ここで返される内部関数はクロージャです
return func_inner
# クロージャ インスタンスを作成します
f = func_out(1)
# クロージャを実行します
f(2)
f(3)

4. クロージャの役割

クロージャは外部関数に変数を保存でき、外部関数が呼び出されても破棄されません。注: クロージャは外部関数の変数を参照するため、外部関数の変数は時間内に解放されず、メモリを消費します。

5. まとめ

① 返された内部関数が外部関数の変数を使用する場合、クロージャが形成されます。 

②クロージャは外部関数の変数を保存できる 

③クロージャ実現のための標準フォーマット:

 
 
 
 

# 外部関数
def test1(a):
b = 10
# 内部関数
def test2():
# 内部関数は外部関数の変数またはパラメータを使用します
print(a, b)
# 内部関数を返します。ここで返される内部関数は次のとおりですクロージャ 例
return test2

クロージャ内で使用される外部変数を変更する

1. クロージャで使用される外部変数を変更します。

間違ったバージョンのデモ:

 
 
 
 

def inner(): #
アウター関数内のローカル変数
num = 10
def inner():
num = 20
print(f'元の変数: {num}') # 10
inner()
print(f'変更された変数: { num} ') # 10
return inner

f = external()

このコードは、別の関数 inner を含む関数 external を定義します。外側の関数では、ローカル変数 num が定義され、値 10 が割り当てられます。内部関数では、同じ名前のローカル変数 num が定義され、値 20 が割り当てられます。ただし、Python のスコープ規則により、内部関数の num は外部関数の num の新しいローカル変数にすぎず、この 2 つは相互に影響しません。したがって、内部関数を呼び出した後も、外部関数の num は 10 のままです。最後に、外側の関数は内側の関数への参照を返し、それを変数 f に割り当てます。このようにして、変数 f は内部関数を呼び出すことができます。

2. クロージャで使用される外部変数を変更します。

正しいバージョンのデモ:

 
 
 
 

def inner():
# 外部関数のローカル変数 num
= 10 def inner():
非ローカル
変数 # 内部関数のローカル変数
num = 20
print(f'元の変数: {num}') # 10 inner()
print (f '変更された変数: {num}') # 20
return inner
f = inner()

このコードは、初期値 10 のローカル変数 num を含む関数 external を定義します。さらに、関数 external は内部関数 inner も定義します。内部関数では、nonlocal キーワードを使用して、num 変数が内部関数のローカル変数ではなく、外部関数のローカル変数であることを宣言します。次に、num の値を 20 に変更し、変更前と変更後の値を出力します。最後に、外側の関数は内側の関数への参照を返し、それを変数 f に割り当てます。このようにして、変数 f は内部関数を指す関数オブジェクトになります。

3. 包括的な閉鎖事例

 
 
 
 

def inner():
result = 0
def inner(num):
非ローカルな結果
result += num
print(result)
return inner
f = inner()
f(1)
f(2)
f(3) # 実行結果について問い合わせる時間は何回ですか?

このコードは、内部関数 inner() を返す関数 external() を定義しており、inner() は、outer() 関数内の変数の結果にアクセスできます。 

関数 external() で、変数 result を定義し、それを 0 に初期化します。次に、パラメータ num を取る内部関数 inner() を定義します。inner() 関数内で、nonlocal キーワードを使用して、結果変数を external() 関数からの変数として宣言し、それを num に追加し、追加するたびに result の値を出力します。最後に、内部関数 inner() を返します。 

次に、関数が呼び出されるときに f = external() を使用して、 inner() 関数を変数 f に代入します。これは、後続のコードで f() 関数を使用して、定義した内部関数を呼び出すことができることを意味します。 

次に、f() 関数を複数回呼び出し、それぞれが内部関数を呼び出して、それに異なるパラメーターを渡します。内部関数では、非ローカル変数 result を使用して前回の呼び出しの結果を記録するため、関数は 3 回目に呼び出されるときに 6 の結果を出力します。したがって、このコードの出力は次のようになります。 

6

デコレーター

1. デコレータの定義

既存の関数に関数を追加する関数であり、本質的にはクロージャ関数です。デコレーターの特徴: 

① 既存機能のソースコードを改変しないでください。 

② 既存関数の呼び出し方法は変更しないでください。 

③既存機能に追加機能を追加する

2. デコレータコード

サンプルコード:

 
 
 
 

# ログイン認証関数を追加します
def check(fn):
def inner():
print("まずログインしてください...")
fn()
return inner


def comment():
print("コメントを投稿")

# 装飾を使用します関数を装飾するデコレータ
comment = check(comment)
comment()

このコードは、関数を引数として受け取り、新しい関数の内部を返すデコレータ関数チェックを定義します。新しい関数 inner が元の関数 fn を実行する前に、「最初にログインしてください」というプロンプト メッセージが出力されます。 

次に、コメントを投稿するために使用される関数 comment を定義します。最後に、デコレータを使用して関数コメントを装飾します。つまり、関数コメントをチェック関数に渡し、返された新しい関数 inner をコメントに割り当てます。 

コードの最後の行は、装飾された関数 comment を呼び出します。この関数は、最初に内部関数のプロンプト情報を実行し、次に元の関数コメントにコメントを投稿する関数を実行します。簡易ログイン認証機能を実装します。

 
 
 
 

# デコレータの基本プロトタイプ
# defdecorator(fn): # fn: ターゲット関数
# def inner():
# ''関数を実行する前に''
# fn() # 装飾された関数を実行します
# ''関数の後に実行''''
# return inner

このコードはデコレーターの基本プロトタイプで、ターゲット関数であるパラメーター fn を受け取るデコレーターと呼ばれる関数を定義します。デコレータ関数内には、inner と呼ばれる関数が定義されており、ターゲット関数の実行の前後にいくつかの操作を実行します。最後に、デコレーター関数は内部関数を返し、ターゲット関数の装飾を実現します。具体的には、関数を定義するときに、@decorator の構文を使用してデコレーター関数をターゲット関数に適用し、ターゲット関数の装飾を実現します。

3. デコレータ用の糖衣構文

  • ログイン認証機能を追加する必要がある関数が複数ある場合、その都度 func = check(func) のようなコードを記述して既存の関数を修飾するのはやはり面倒です。

  • Python では、より簡単に装飾関数を記述する方法として、シュガー構文が用意されています。シュガー構文の記述形式は @decorator 名であり、既存の関数の装飾もシュガー構文を通じて行うことができます。

 
 
 
 

# ログイン認証関数を追加
def check(fn):
print("デコレータ関数が実行されます")
def inner():
print("まずログインしてください...")
fn()
return inner

変換

 
 
 
 

# 糖衣構文を使用して関数を装飾します
@check
def comment():
print("Post a comment")

comment()

デコレーターの役割

1. デコレータの使用シナリオ

  1. 統計的なプログラム実行時間: 関数の開始時刻と終了時刻を記録するデコレーターを作成し、関数の実行時間を計算できます。このデコレータは、プログラムのパフォーマンスの最適化やデバッグに使用できます。

  2. 補助システム関数出力ログ情報: 関数の実行プロセスを記録し、ログ情報を出力するデコレータを作成できます。このデコレータは、デバッグ、監視、エラー処理に使用できます。

2. デコレーターは既存関数の実行時間の統計を実現します。

 
 
 
 

import time
def get_time(func):
def inner():
# 開始タイミング
begin = time.time()
func()
# 終了タイミング
end = time.time()
print("関数の実行コスト %f" % (end - begin) ))

内部を返す

このコードは、関数を引数として受け取るデコレータ関数 get_time を定義します。ネストされた関数 inner はデコレーター関数内で定義され、受信関数 func をラップするために使用されます。内部関数は、func を呼び出す前後の時間を記録し、関数の実行時間を計算し、最後に関数の実行にかかった時間を出力します。

デコレータ関数 get_time は内部関数、つまり新しい関数を返しますが、この新しい関数の機能は、元の関数の実行前後の時間を記録し、実行時間を出力することです。デコレータ @get_time を使用して、時間を計測する必要がある関数にこのデコレータを適用すると、関数の実行時間を簡単に取得できます。に変換

 
 
 
 

@get_time
def デモ():
範囲(100000)のiの場合:
print(i)

デモ()

このコードは、デコレーター関数 @get_time を定義し、それを関数 demo() に適用します。デコレータ関数@get_timeの機能は、関数demo()の実行前後で現在時刻を記録し、時差を2回計算し、最終的に時差を出力することです。 

関数デモ() にはループが含まれており、ループ数は 100000 で、各ループは値を出力します。demo() 関数が呼び出されると、ループが実行されて値が出力され、さらにデコレーター関数 @get_time の実行がトリガーされて、関数の実行時間が出力されます。

汎用デコレータの使用

 

1. デコレータの使用シナリオ

  1. 統計的なプログラム実行時間: 関数の開始時刻と終了時刻を記録するデコレーターを作成し、関数の実行時間を計算できます。このデコレータは、プログラムのパフォーマンスの最適化やデバッグに使用できます。

  2. 補助システム関数出力ログ情報: 関数の実行プロセスを記録し、ログ情報を出力するデコレータを作成できます。このデコレータは、デバッグ、監視、エラー処理に使用できます。

2. デコレーターは既存関数の実行時間の統計を実現します。

 
 
 
 

import time
def get_time(func):
def inner():
# 開始タイミング
begin = time.time()
func()
# 終了タイミング
end = time.time()
print("関数の実行コスト %f" % (end - begin) ))

内部を返す

このコードは、関数を引数として受け取るデコレータ関数 get_time を定義します。ネストされた関数 inner はデコレーター関数内で定義され、受信関数 func をラップするために使用されます。内部関数は、func を呼び出す前後の時間を記録し、関数の実行時間を計算し、最後に関数の実行にかかった時間を出力します。

デコレータ関数 get_time は内部関数、つまり新しい関数を返しますが、この新しい関数の機能は、元の関数の実行前後の時間を記録し、実行時間を出力することです。デコレータ @get_time を使用して、時間を計測する必要がある関数にこのデコレータを適用すると、関数の実行時間を簡単に取得できます。に変換

 
 
 
 

@get_time
def デモ():
範囲(100000)のiの場合:
print(i)

デモ()

このコードは、デコレーター関数 @get_time を定義し、それを関数 demo() に適用します。デコレータ関数@get_timeの機能は、関数demo()の実行前後で現在時刻を記録し、時差を2回計算し、最終的に時差を出力することです。 

関数デモ() にはループが含まれており、ループ数は 100000 で、各ループは値を出力します。demo() 関数が呼び出されると、ループが実行されて値が出力され、さらにデコレーター関数 @get_time の実行がトリガーされて、関数の実行時間が出力されます。

汎用デコレータの使用

1. 関数をパラメータで装飾する

 
 
 
 

deflogging(fn):
def inner(num1, num2):
print('-- 計算しようとしています--')
fn(num1, num2)
return inner

@logging
def sum_num(num1, num2):
result = num1 + num2
print (結果)

sum_num(10, 20)

このコードは、関数 fn を引数として取るデコレータ関数レコードを定義します。ロギングは内部関数 inner を返します。この関数は 2 つのパラメータ num1 と num2 を受け取り、fn を呼び出す前にメッセージを出力します。最後に、ログは内部関数を返します。

@logging は、デコレータ関数のレコードを次の関数 sum_num に適用できるデコレータ構文です。これは、sum_num が内部関数として再定義されることを意味します。つまり、sum_num の呼び出しは実際には内部関数の呼び出しとなります。 

sum_num 関数内で、num1 と num2 の合計を計算し、結果を出力します。sum_num はロギング デコレータによって変更されるため、sum_num が呼び出される前にメッセージが出力されます。最後に、 sum_num(10, 20) を呼び出すと、次の出力が得られます。 

--計算しようとしています-- 

30

2. 関数を戻り値で修飾する

 
 
 
 

deflogging(fn):
def inner(num1, num2):
print('--計算しようとしています--')
result = fn(num1, num2)
return result
return inner

@logging
def sum_num(num1, num2):
result = num1 + num2
戻り結果

print(sum_num(10, 20))

このコードは、関数を引数として受け取り、新しい関数の内部を返すデコレーター関数レコードを定義します。内部関数は、元の関数を実行する前に「--計算に苦労しています--」というメッセージを出力し、次に元の関数を実行して、最後に元の関数の戻り値を返します。 

次に、@logging デコレータを使用して関数 sum_num を修飾します。これは、sum_num 関数をロギング関数に渡し、返された新しい関数を sum_num に再割り当てするのと同じです。このように、sum_num 関数が呼び出されると、実際には内部関数が実行されます。 

最後に、sum_num 関数が呼び出され、パラメーター 10 と 20 が渡され、出力結果は 30 になります。同時に、「-- 計算しようとしています--」というメッセージも出力されます。

3. 関数を可変長パラメータで修飾する

 
 
 
 

def logg(fn):
def inner(*args, **kwargs):
print('--計算しようとしています--')
fn(*args, **kwargs)
return inner

このコードは、関数 fn を引数として受け取り、関数 inner を返すデコレータ関数レコードを定義します。 

関数 inner は、任意の数の位置引数およびキーワード引数を受け取り、fn 関数を実行する前に「-- 評価を試行しています --」というメッセージを出力します。次に、関数 inner は fn 関数を呼び出し、同じパラメーターを渡します。 

このデコレータ関数を使用すると、他の関数にログ情報を追加し、関数の実行開始、実行終了など、関数の実行時に役立つ情報を出力できます。

 
 
 
 

@logging
def sum_num(*args, **kwargs):
result = 0
for i in args:
result += i

for i in kwargs.values():
result += i
print(result)

sum_num(10, 20, a=) 30)

このコードは、任意の数の位置引数とキーワード引数を入力として受け取り、それらを合計する関数 sum_num() を定義します。関数内では、最初にすべての位置パラメータが追加され、次にすべてのキーワード パラメータの値が追加され、最後に 2 つの合計が出力されます。 

コード内のデコレーター @logging は、関数が実行されると (この関数は指定されていません)、logging という名前の関数が呼び出されることを示します。この関数は、関数の実行 (開始時刻、終了時刻、パラメーター値など) を記録する可能性があります。 。)。このようにして、関数を呼び出すときに出力を記録およびログに記録できるため、デバッグやトラブルシューティングに便利です。 

最後に、60 を出力する関数 sum_num(10, 20, a=30) を呼び出します。これは、10 と 20 は合計が 30 になる位置パラメーターであり、a=30 は値が 30 のキーワード パラメーターであるため、合計は 60 になるためです。 

操作結果:

4. ユニバーサルデコレータ

 
 
 
 

# ログを出力する関数を追加
deflogging(fn):
def inner(*args, **kwargs):
print("--計算しようとしています--")
result = fn(*args, **kwargs)
return result

return内側

このコードは、関数 fn を引数として受け取り、新しい関数 inner を返すデコレータ関数レコードを定義します。 

新しい関数 inner は、任意の数の位置引数およびキーワード引数を受け入れ、関数の実行前に評価が進行中であることを示すログを出力します。次に、元の関数 fn を呼び出し、その結果を返します。 

このデコレーター関数を他の関数に適用することで、関数が実行されるたびにログが出力されるように、ログを出力する機能を追加できます。例えば:

 
 
 
 

@logging
def add(a, b):
a + bを返します

add(2, 3) が呼び出されると、「--trying to compute--」と出力され、5 が返されます。

 
 
 
 

# 糖衣構文を使用して関数を装飾します
@logging
def sum_num(*args, **kwargs):
result = 0
for value in args:
result += value

for value in kwargs.values():
result += value

return result


@logging
def 減算 (a, b):
結果 = a - b
print(result)

このコードは 2 つの関数を定義しており、これらはデコレーター @logging で修飾されています。

デコレータ @logging は、他の関数を装飾するために使用される関数です。その機能は、コード実行のデバッグと追跡を容易にするために、装飾された関数の実行前後にログ情報を出力することです。 

関数 sum_num(args, *kwargs) は、渡されたすべての引数の合計を計算する可変引数関数です。その引数リストには、可変位置パラメータ args と可変キーワード パラメータ kwargs が含まれます。関数本体はループを使用して args と kwargs.values() を走査し、それらの値を追加して結果を返します。 

関数subtraction(a, b)は、aとbの差を計算し、結果を出力する単純な関数です。関数本体にはコードが 1 行だけあります。 

これら 2 つの関数はデコレータ @logging で修飾されているため、ログ情報は実行の前後に出力されます。これらのログ情報には、関数名、パラメータのリスト、戻り値などが含まれます。これにより、関数の実行のトレースとコードのデバッグが簡単になります。

 
 
 
 

result = sum_num(1, 2, a=10)
print(result)

減算(4, 2)

このコードでは、2 つの関数 sum_num() とsubtraction() を定義し、それらを呼び出します。これらのコードの詳細な説明は次のとおりです。 

パート 1: 関数の定義 

1. sum_num(1, 2, a=10): 2 つの位置引数と a という名前のキーワード引数を受け入れる sum_num() という名前の関数を定義します。この関数は、2 つの位置引数と a の値の合計を返します。 

2.subtraction(4, 2):subtraction() という関数を定義します。この関数は 2 つの位置パラメータを受け取り、2 つのパラメータの差を返します。 

パート 2: 関数の呼び出し 

1. result = sum_num(1, 2, a=10): sum_num() 関数を呼び出し、パラメータ 1 と 2 を位置パラメータとして、10 をキーワード パラメータ a の値として渡します。関数の実行後、1 + 2 + 10 = 13 を返し、この結果を結果変数に代入します。 

2. print(result): result 変数の値 (13) を出力します。 

3. 減算(4, 2): 減算() 関数を呼び出し、パラメータ 4 と 2 を位置パラメータとして渡します。関数の実行後、4 - 2 = 2 が返されますが、この結果は変数に格納されず、出力されません。

パラメータを使用したデコレータの概要

1. パラメータを使用したデコレータの概要

パラメーターを持つデコレーターは、デコレーターを使用して関数を装飾するときに、指定されたパラメーターを渡すことができることを意味します。構文形式は次のとおりです: @decorator(parameter,...)

エラーデモ

 
 
 
 

defdecorator(fn, flag):
def inner(num1, num2):
if flag == "+":
print("--作業加算計算--")
elif flag == "-":
print("-- Working減算計算時 --")
result = fn(num1, num2)
return result
return inner

これは、関数とフラグの 2 つの引数を取るデコレーター関数です。内部関数 inner を返します。 

内部関数は、異なるフラグに従って異なるプロンプト情報を出力します。次に、受信関数 fn を呼び出し、2 つのパラメーター num1 と num2 を渡し、結果を返します。最後に結果が呼び出し元に返されます。 

デコレーター関数の機能は、元の関数のコードを変更せずに、関数に追加の関数を追加することです。この例では、デコレータ関数によって加算関数と減算関数にヒントを追加して、プログラムをより使いやすくすることができます。

 
 
 
 

@decorator('+')
def add(a, b):
result = a + b
return result

result = add(1, 3)
print(result)

これはデコレータ関数です。デコレーター関数は、ソース コードを変更せずに機能を追加したり、関数の動作を変更したりできます。ここで、デコレータ関数は 2 つの数値を記号「+」で加算し、計算結果を返します。 

このデコレータ関数は add(a, b) 関数に適用され、2 つの引数を加算して結果を返します。したがって、add(a, b) 関数が呼び出されると、デコレーター関数内のロジックが実際に実行されます。この関数は 2 つの引数を追加し、計算の結果を返します。 

最後に、add(1, 3) 関数がインスタンス化され、結果 (4) が出力されます。結果:

 
 
 
 

トレースバック (最新の呼び出しは最後):
ファイル "/home/python/Desktop/test/hho.py"、行 12、<モジュール>
@decorator('+')
TypeError:decorator() に必要な位置引数が 1 つありません: '国旗'

2. 正しい文法

@ 記号の後にデコレータ インスタンスが続く必要があるため、デコレータの外側で関数をラップし、最も外側の関数がパラメータを受け取ってデコレータを返します。

 
 
 
 

# ログ出力機能を追加
deflogging(flag):

defdecorator(fn):
def inner(num1, num2):
if flag == "+":
print("--作業加算計算--")
elif flag = = "-":
print("--減算計算中--")
result = fn(num1, num2)
return result
return inner

# return デコレータ
return デコレータ

このコードは、文字列パラメータ フラグを受け取り、デコレータ関数デコレータを返すデコレータ関数ロギングを定義します。 

デコレータ関数は関数 fn を引数として取り、2 つの引数 num1 と num2 を取る内部関数 inner を定義します。内部関数では、渡されたフラグの値に応じて、対応するログ情報を出力し、元の関数 fn を呼び出し、その結果を返します。 

最後に、デコレータ関数は内部関数をデコレータとして返し、デコレータ関数に適用されます。このように、装飾された関数が呼び出されると、最初に対応するログ情報が出力され、その後、元の関数が実行されます。

 
 
 
 

# デコレータを使用して関数を装飾します
@logging("+")
def add(a, b):
result = a + b
return result

@logging("-")
def sub(a, b):
result = a - b
結果を返します

結果 = add(1, 2)
print(result)
結果 = sub(1, 2)
print(result)

このコードは、加算と減算をそれぞれ実装する 2 つの関数 add と sub を定義します。同時に、デコレータ @logging を使用して、これら 2 つの関数を装飾します。デコレータ関数ロギングは、関数の実行前後のログ情報を出力します。ログのプレフィックスとして「+」と「-」が使用されます。情報。最後に、add 関数と sub 関数をそれぞれ呼び出し、その戻り結果を出力します。

クラスデコレーターが使用するのは、

1. クラスデコレータの紹介

デコレータのもう 1 つの特殊な用途はクラス デコレータです。これは、クラスを定義することによって関数を装飾します。

 
 
 
 

class Check(object):
def __init__(self, fn):
# 初期化操作はここで完了
self.__fn = fn

# __call__ メソッドを実装します。これは、関数を呼び出すようにクラスを呼び出すことを意味します。
def __call__(self, *args, **kwargs):
# 装飾関数を追加
print("最初にログインしてください...")
self.__fn()

このコードは、デコレーター クラス Check を定義します。このクラスは、ユーザーがログインしているかどうかのチェックなど、装飾された関数が実行される前にいくつかの操作を実行するために使用されます。 

クラスの初期化メソッド init で、インスタンス属性 fn に装飾関数 fn を保存します。特別なメソッド呼び出しがクラス内で定義されており、クラス インスタンスが関数のように呼び出されたときに実行されます。callメソッドでは、まずプロンプトメッセージを出力してから、fn属性に格納された関数を呼び出します。 

このデコレータを使用して関数を修飾する場合、実際には Check クラスのインスタンスを作成し、修飾された関数をパラメータとしてインスタンスの初期化メソッド init に渡し、そのインスタンスを関数の新しい定義として使用します。したがって、デコレータ関数を呼び出す際には、実際にはCheckクラスのインスタンスを呼び出し、さらにcallメソッドを呼び出すことでデコレータの機能を実現します。

 
 
 
 

@Check
def comment():
print("コメント")

comment()

2. コードの説明

@Check は comment = Check(comment) と同等であるため、init メソッドを提供し、追加の fn パラメータを追加する必要があります。 

クラスのインスタンス オブジェクトを関数のように呼び出したい場合は、クラスの call メソッドを使用して、クラスのインスタンスを呼び出し可能なオブジェクト (callable) に変える必要があります。つまり、呼び出すことができます。関数のように。 

call メソッド内で fn 関数を修飾して関数を追加します。

 

おすすめ

転載: blog.csdn.net/Blue92120/article/details/131332567