デコレータ機能を学習する前に、次の2つのシナリオを検討してください。
a.
関数fnがあり、関数のソースコードを変更することはできませんが、関数の関数を実現するにはどうすればよいですか? ****
新しい関数decoを定義してから、 fn = deco(fn)**のような割り当て操作を実行すると、元のfnが呼び出されたときに、実際にdeco(fn)操作が実行されます。このメソッドが機能する場合、次の問題に直面しています。
デコ関数は関数をパラメータとして受け入れる必要があり、デコ関数も関数を返す必要があります。明らかに、受け入れられる関数は関数fnである必要があり、返される関数はfnの関数と拡張関数の両方を持っている必要があります。したがって、デコ関数の構造は次のようになります。
def deco(fn):
def wrapper(*args,**kwargs): #ここでのパラメーターの目的は、fn関数に渡すことです。.
CODE ... #New function code if any
fn(*args,**kwargs)
CODE ... #New function code if any
return wrapper
# 呼び出し方法は次のとおりです。
fn=deco(fn)fn(*args,**kwargs) #fn関数の呼び出し方法は変更されません
b.
**関数ラッパーがありますが、関数の呼び出し方法を変更せずに、関数ラッパーに追加のパラメーターを渡すにはどうすればよいですか? ****
** wrapper = func(args)**のように、割り当てによってラッパーを変更できます。ここで、argsは渡す追加のパラメーターであり、funcは新しい関数です。func関数には次のものが必要です。
渡す追加のパラメーター引数を受け入れ、同時に関数を返す必要があります。返される関数はラッパー関数である必要があります。渡されたパラメーター引数がラッパー関数にどのように与えられるかについては、ラッパーコードでこのパラメーターを受け入れる必要があります。可能な構造は次のとおりです。
def func(args):
CODE.... #Code if any required.
tmp_para=args #tmpを使用して、追加のパラメーターargsを受け入れます
def wrapper():
extra_para=tmp_para #ラッパー関数に渡される追加のパラメーター引数を実装します.
CODE... #ラッパー関数のコード。
return wrapper
CODE.... #存在する場合、コードのこの部分は処理パラメーターに関連付けることができます。
# 呼び出し方法は次のとおりです。
wrapper=func(args) #argsは、渡される追加のパラメーターです。
wrapper(*args,**kwargs) #それらはラッパー自体のパラメーターです
**上記の2つのケースでは、**を達成しました。
A. fn = deco(fn)を割り当てることにより、関数fnの関数は、関数のソースコードを変更せずに拡張されます。
B.wrapper = func(args)を割り当てることにより、新しい関数funcを使用して追加のパラメーターをラッパー関数に渡しますが、ラッパー関数のソースコードを変更する必要があります。ラッパー関数のソースコードを変更できない場合は、追加のパラメーターをに渡します。ラッパーのポイントは何ですか?
例を見てみましょう:
#! /usr/bin/env python
# - *- coding:utf-8-*-
# Author: PandaEye
def welcome(name): #A very simple function.print("Welcome to my blog: %s !"% name)
def wrapper(gift):
ext_para=gift #Extra parameter is : gift , pass it to function deco.
def deco(fn): #The deco extend the function and no change the code of fn.
def fun(*args,**kwargs):print("I am the new function, send you 10 points more for congratulations!")fn(*args,**kwargs)print("Congratulations, you got the 1st, send the gift %s to you !"% ext_para)return fun
return deco
deco=wrapper("BMW")
welcome=deco(welcome)welcome("XiaoMa")
上記の例では、メインプログラムのwelcome関数の呼び出しメソッドは変更されていませんが、関数は2回拡張されています。
その中で、デコ機能が初めて拡張に使用されます。
decoの最初の拡張に基づいて、追加のパラメーターgiftをdecoに渡す必要があります。これは、decoが受け入れるパラメーターはfnでなければならないため、明らかに直接decoに渡すことはできません。そのため、ラッパー関数を使用して渡します。パラメーターをに渡すデコの後、デコを変更しました。デコは着信パラメータを処理する必要があるため、デコのコードを変更する必要があります。これまでに、2つの拡張が完了しました。
上記のプロセスを理解した後、あなたは実際にデコレータ機能、デコレータ機能を理解します:
デコレータ関数は、実際には上記の2行の割り当てコードを@wrapper( "BMW")に変換してから、位置を調整します。デコレータ関数の書き込み処理用。
以下は、上記の例で一般的に使用されているデコレータの表現です。2つは非常によく似ています。上記の呼び出しを理解すると、このデコレータ機能を理解できます。
#! /usr/bin/env python
# - *- coding:utf-8-*-
# Author: PandaEye
def wrapper(gift):
ext_para=gift #Extra parameter is : gift , pass it to function deco.
def deco(fn): #The deco extend the function and no change the code of fn.
def fun(*args,**kwargs):print("I am the new function, send you 10 points more for congratulations!")fn(*args,**kwargs)print("Congratulations, you got the 1st, send the gift %s to you !"% ext_para)return fun
return deco
# deco=wrapper("BMW")
# welcome=deco(welcome)
@ wrapper("BMW") #このステートメントは、デコレータ関数の一般的な表現である、すぐ上の2つのステートメントと同じ効果があります。,デコレータ関数を呼び出す前に、最初に定義する必要があるため、ラッパー関数の定義はこの文の前にある必要があります。そうしないと、エラーが報告されます。
def welcome(name): #A very simple function.print("Welcome to my blog: %s !"% name)welcome("XiaoMa")