ホームページ  >  記事  >  バックエンド開発  >  デコレータの詳細な説明と例

デコレータの詳細な説明と例

高洛峰
高洛峰オリジナル
2017-03-28 16:18:101642ブラウズ

デコレータ

1. デコレータ: 本質的には

関数

2. 関数: 他の関数を装飾し、他の関数に追加の関数を追加するために使用されます

2. 関数を変更することはできません。装飾された関数のソースコード

2. 装飾された関数の呼び出しメソッドは変更できません

3. 関数の概念を

変数として実装

2. 3. 入れ子関数

>> 高階関数 + 入れ子関数 = デコレータ

IV. 関数は変数 1. 上の例では、変数「x」を定義しました。 " と関数 test() を使用すると、メモリ内の変数と関数の位置をそれぞれ出力します。 print(test) が print("関数名") の場合、関数のメモリ アドレスを出力できることがわかります。

次のコードを見てみましょう:

x = 1
print(id(x))
def test():
	pass
print(test)
#输出
1842348496
<function></function>

関数名testをfに代入してf()を実行すると、関数が正常に実行できていることがわかり、test関数の実行結果になります。したがって、これは次のコードに似ています:

def test():
	print("in the test.")
f=test
f()
#输出
in the test.

次のような類推ができます。関数名 test は x に相当し、関数本体は 1 に相当し、f は y に相当します。

2.

pythonにおけるメモリの表現

緑色の四角をメモリとみなし、小さな四角はそれぞれメモリ内の変数や関数のアドレスです。

変数名

(x) や関数名 (test) については、番地と鮮やかに比較できます。変数または関数を呼び出す必要がある場合、その番地を参照してメモリ アドレスを見つけてそれを返すだけで済みます。 test() などの関数を実行するには () のみを追加する必要があります。

変数の呼び出しは実際には変数のメモリアドレスを参照するため、関数名を呼び出すことで関数本体のメモリアドレスも取得できます。関数名を変数名として関数に渡すことができます。つまり、関数は変数です。関数をパラメータとして取る関数は高階関数です。

5. 高階関数

次のいずれかの条件を満たす関数です

デコレータの詳細な説明と例1. 関数名を実パラメータとして他の関数に渡します

2. 戻り値には関数名が含まれます。 1) パラメータとしての関数名

x = 1
y = x
print(y)
#输出
1

上記の例では、関数 test1 を定義し、高階関数 test2 も定義しました。 test1 関数名をパラメータとして test2 に渡します。これにより、このような関数を実現し、元の test1 関数に実行時間を計算する関数を追加できます。これはデコレータに少し似ていますが、一貫していることが 1 つあります。それは、上記の高階関数 test2 が関数の呼び出し方法を変更していることです。

ただし、装飾された関数は変更せずに、新しい関数を追加しました。

2) 戻り値には関数名が含まれています

import time
def test1():
	time.sleep(2)
	print("in the test1.")
def test2(func):
	start_time = time.time()
	func()
	stop_time = time.time()
	print("The action time of program is {}".format(stop_time-start_time))
test2(test1)
#输出
in the test1.
The action time of program is 2.0012054443359375

上記の例では、最終的に高階関数test2(test1)をtest1に代入し、再度test1関数を呼び出しています。この例では、test1 関数の呼び出し方法が変わっていないことが直感的にわかります。ただし、新しい機能は追加されないため、ネストされた関数を使用する必要があります。

6. 入れ子関数

関数本体には別の関数の完全な定義があり、これが入れ子関数です。

1) 定義:

def test1():
	time.sleep(2)
	print("in the test1.")
def test2(func):
	print(func)
	return func
test1 = test2(test1)
test1()
#输出
<function>
in the test1.</function>

次のように、関数コンテンツ内で関数を呼び出すだけでは、入れ子関数ではありません:

def foo():
	print("in the foo")
	def bar():
		print("in the bar")
	bar()
foo()

2) 入れ子関数のスコープ

ローカル スコープとグローバル スコープのアクセス順序

def test1():
    print("in the test1.")
def test2():
    test1()

3) 入れ子関数を使用して、変更した関数に新しい関数を追加します

2 番目の高階関数の例では、元の関数の呼び出し方法を変更せずに実現しました。新しい関数を追加する必要がある場合は、変更された内容が戻り値、つまり return func に存在する必要があります。この関数を実装するためにネストされた関数を定義できます。

x = 0
def grandpa():
	x = 1
	def dad():
		x = 2
		def son():
			x = 3
			print(x)
		son()
	dad()
grandpa()
#输出
3

timer()内に入れ子関数deco()を定義し、変更した関数に実行時間を加算する機能を実装します。 timer() 関数は deco() のメモリ アドレスを返します。このメモリ アドレス deco は参照することも、test1 に直接割り当てることもできます。このようにして、test1() を直接実行することができ、デコレータの機能を実現できます。

7. デコレータ

Python は、関数定義の前にデコレータ名と @ 記号を追加することで関数をラップします

import time
def timer(func):  # timer(test1) func = test1
	def deco():
		start_time = time.time()
		func()   # run test1()
		stop_time = time.time()
		print("the action time of the program is {}".format(stop_time-start_time))
	return deco   # 返回了deco的内存地址
def test1():
	time.sleep(2)
	print("in the test1.")
test1 = timer(test1)
test1()
# 输出 
in the test1.
the action time of the program is 2.0003786087036133

以上がデコレータの詳細な説明と例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。