pythonデコレータが不明瞭にならないようにする

デコレータ機能を学習する前に、次の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")

この記事はオリジナルです。再版のソースを教えてください!

Recommended Posts

pythonデコレータが不明瞭にならないようにする
Pythonの初心者はデコレータを学びます