変数の役割ドメインの観点からpython装飾器を一歩一歩理解する


デザイナは、関数やクラスをカプセル化するためのツールであり、ログの挿入、パフォーマンステスト、トランザクション、パーミッションチェックなどのビジネスロジックの中で、Flaskのルーティングテーブルがデザイナを使用しているなど、いくつかのアプリケーションシーンで使用されます.重複コードを減らすのに役立ち、拡張性が高い.
本編では主に以下のように紹介する.
1)pythonのローカル変数とグローバル変数
2)python閉パッケージ、閉パッケージは変数、デザイナに関連付けられている
3)pythonデコレーション
一、pythonのローカル変数とグローバル変数
グローバル変数はpyファイル全体で機能し、ローカル変数は関数内で定義され、関数内でのみ機能する変数です.
1.1ローカル変数とグローバル変数は同じ名前で、ローカル変数を変更しても、グローバル変数は変更されません.
#!/usr/bin/python  
# -*- coding: utf-8 -*-  
b = 6
def f1(a):
	print a
	b = 5
	print b
f1(3)
print b

結果
3

5

6

1.2.関数の内部でローカル変数を直接使用するとエラーが発生します.
#!/usr/bin/python 
# -*- coding: utf-8 -*- 
b = 6
def f1(a):
      print a
      print b
      b = 5

f1(3)

結果:
F:\test>python test.py

  File"test.py", line 9

    b = 5

        ^

IndentationError: unindent does not match anyouter indentation level

なぜならpythonはtestをコンパイルしているからです.pyの時関数f 1の場合、bは局所変数であると判断しますが、bを印刷するとバインド値がないことがわかります.
1.3.関数内でグローバル変数を使用しglobalで修飾
#!/usr/bin/python 
# -*- coding: utf-8 -*-  

b = 6

def f1(a):
      globalb
      printb
      b =5   

f1(3)
print b 

結果:
6

5

二、閉包
閉パッケージとは、関数を定義するときに存在する自由変数のバインドを保持する役割ドメインを延長する関数です.
#!/usr/bin/python 

# -*- coding: utf-8 -*- 

def count():

   a = 1

   def sum():

        c = 1

        return a + c  # a     

   return sum

count_tmp = count()

print count_tmp ()

結果:
2

関数countは全体的に閉パケットであり,aは自由変数であり,以上を押すとaは局所変数でありsum関数を呼び出すとaは既に戻っているが,aのバインドは依然として使用できる.
可変オブジェクトと非可変オブジェクトの参照:https://www.cnblogs.com/sun-haiyu/p/7096918.html
pythonの可変オブジェクトとは、オブジェクトが指すメモリの値が変更できないことを意味し、オブジェクトを操作すると、数値タイプint、float、文字列str、メタグループtupleなどの再変更が再コピーされます.
可変オブジェクトとは、リスト、辞書、コレクションsetなど、操作アドレスが変更されないオブジェクトを指す.
2.1自由変数が可変オブジェクトの閉パッケージ
次の例のように、自由変数はリストです.
#!/usr/bin/python 

# -*- coding: utf-8 -*-  

from __future__ import division 

def make_averager():

      series= []    

      defaverage(new_value):

           series.append(new_value)

           total= sum(series)

           returntotal / len(series)          

      returnaverage     

avg = make_averager()

print avg(10)

print avg(11)

print avg(12)

結果:
10.0

10.5

11.0

    from __future__ import divisionは正確な除算を採用しており、make_を呼び出すことができます.averager()の場合、averageオブジェクトが返され、averageが呼び出されるたびに、履歴に追加された新しい値が可変オブジェクトaverageに保存され、現在の平均値が計算されます.
2.2自由変数が可変オブジェクトである閉パッケージ
#!/usr/bin/python 
# -*- coding: utf-8 -*- 
from __future__ import division
def make_averager():
       count= 0
       total= 0   
       defaverage(new_value):

              count+= 1

              total+= new_value

              returntotal / count            

       returnaverage

avg = make_averager()

print avg(10)


結果:
t0 is 2.05261256527e-06

will sleep 5 seconds

t1 is 5.00363380844 

countは可変オブジェクトであるため、count操作に1を加えると自由変数countがローカルオブジェクトになり、ローカルオブジェクトcountが割り当てられていないまま使用されるとエラーが発生します.
閉パッケージでは、可変オブジェクトは読み取りのみで更新はできません.更新すると、暗黙的にローカル変数が作成され、この変数は閉パッケージに保存されません.
解決策:Python 3はnonlocal宣言を導入し、その役割は変数を自由変数として宣言することであり、nonlocal宣言の変数に新しい値を与えても自由変数となり、閉パッケージに保存される.
 
三、装飾器
3.1アクセラレータと関数のインタラクション
#!/usr/bin/python 

# -*- coding: utf-8 -*-  

import time 

def clock(func):

      defclocked(*args):

           t0= time.clock()

           print"t0 is %s"% t0

           result= func(*args)

           t1= time.clock()

           print"t1 is %s" % t1

           returnresult

      returnclocked

@clock

def snooze(seconds):

      print"will sleep %s seconds" % seconds

      time.sleep(seconds)

snooze(5)

結果:
t0 is 2.05261256527e-06

will sleep 5 seconds

t1 is 5.00363380844

@clockは装飾器文法で、装飾器を表し、snoizeは装飾された関数です.
@clock

def snooze(seconds):

      print"will sleep %s seconds" % seconds

      time.sleep(seconds)

次のように等価です.
def snooze(seconds):

      print"will sleep %s seconds" % seconds

      time.sleep(seconds)

snooze = clock(snooze)

clock全体は閉パケットと見なすことができ、funcは自由変数であるため、clockedはこの自由変数を使用することができる.clockを呼び出し、clockedを返すと、snoize(5)を呼び出すことはclocked(5)を呼び出すことに相当する.このときsnoizeはclockedの参照になります.
したがって、ここで装飾器の役割はclocked()関数がプログラムの実行時間を印刷することを保証することです.
t0 is2.05261256527e-06

t1 is 5.00363380844

また、被装飾関数snoizeによって5秒間休眠する機能を追加します.
 will sleep 5 seconds

参考資料『流暢なPython』