python裝飾器python
一:函數調用順序:其餘高級語言相似,Python 不容許在函數未聲明以前,對其進行引用或者調用
錯誤示範:shell
def foo(): print 'in the foo' bar() foo() 報錯: in the foo Traceback (most recent call last): File "<pyshell#13>", line 1, in <module> foo() File "<pyshell#12>", line 3, in foo bar() NameError: global name 'bar' is not defined
def foo(): print 'foo' bar() foo() def bar(): print 'bar' 報錯:NameError: global name 'bar' is not defined
正確示範:(注意,python爲解釋執行,函數foo在調用前已經聲明瞭bar和foo,因此bar和foo無順序之分)
閉包
def bar(): print 'in the bar' def foo(): print 'in the foo' bar() foo() def foo(): print 'in the foo' bar() def bar(): print 'in the bar' foo()
二:高階函數
app
知足下列條件之一就可成函數爲高階函數ide
把一個函數名當作實參傳給另一個函數(在不修改被裝飾器函數源代碼的狀況下爲其添加功能)函數
函數的返回值包含n個函數,n>0(不修改函數的調用方式)spa
高階函數示範:code
def bar(): print 'in the bar' def foo(func): res=func() #res=func()=bar() return res #返回函數執行的結果 foo(bar) #執行函數foo(bar),把bar函數做爲參數傳入
高階函數的牛逼之處:內存
def bar(): time.sleep(3) print('in the bar') def foo(func): return func #返回函數的內存地址 print(foo(bar)) #打印出函數bar的內存地址 foo(bar)() #執行foo(func)函數 bar=foo(bar) #賦值給變量bar,在python中裝飾器使用@foo代替 bar() #執行變量bar()函數
三:內嵌函數和變量做用域utf-8
定義:在一個函數體內建立另一個函數,這種函數就叫內嵌函數(基於python支持靜態嵌套域)
(在一個函數的函數體內,用def聲明一個函數,而不是調用一個函數)
函數嵌套示範:
def foo(): def bar(): print 'in the bar' bar() foo() # bar()
局部做用域和全局做用域的訪問順序
x=0 def grandpa(): # x=1 def dad(): x=2 def son(): x=3 print x son() dad() grandpa()
局部變量修改對全局變量的影響
y=10 # def test(): # y+=1 # print y def test(): # global y y=2 print y test() print y def dad(): m=1 def son(): n=2 print '--->',m + n print '-->',m son() dad()
四:閉包:若是在一個內部函數裏,對在外部做用域(但不是在全局做用域)的變量進行引用,那麼內部函數就被認爲是 closure
def counter(start_num=0): count=[start_num] def incr(): count[0]+=1 return count[0] return incr print counter() print counter()() print counter()() c=counter() print c() print c()
五:內嵌函數+高階函數+閉包=》裝飾器
裝飾器:
定義:本質是函數,(裝飾其它函數)就是爲其它函數添加附加功能
原則:
1.不能修改被裝飾的函數的源代碼
2.不能修改被裝飾的函數的調用方式
預熱兩個範例:
範例一:函數參數固定
def decorartor(func): def wrapper(n): print('starting') func(n) print('stopping') return wrapper # 執行decorartor函數,返回wrapper函數內存地址 def test(n): print('in the test arg is %s' % n) decorartor(test)('alex') #decorartor(test) 等於 return wrapper函數內存返回值 #decorartor(test)(alex) = wrapper(alex) 執行函數 #decorartor(test)(alex):func等於函數名,n等於上面函數名帶的參數
範例二:函數參數不固定
def decorartor(func): def wrapper(*args,**kwargs): print 'starting' func(*args,**kwargs) print 'stopping' return wrapper def test(n,x=1): print 'in the test arg is %s' %n decorartor(test)('alex',x=2)
1.無參裝飾器
import time def decorator(func): #decorator(test) func=test def wrapper(*args,**kwargs): start=time.time() func(*args,**kwargs) #run test() stop=time.time() print 'run time is %s ' %(stop-start) print timeout return wrapper #返回一個變量的內存地址 @decorator #至關於test=decorator(test)=wrapper test()=wrapper()"執行wrapper變量" def test(list_test): for i in list_test: time.sleep(0.1) print '-'*20,i #decorator(test)(range(10)) test(range(10))
2.有參裝飾器
import time def timer(timeout=0): def decorator(func): def wrapper(*args,**kwargs): start=time.time() func(*args,**kwargs) stop=time.time() print 'run time is %s ' %(stop-start) print timeout return wrapper return decorator @timer(2) def test(list_test): for i in list_test: time.sleep(0.1) print '-'*20,i #timer(timeout=10)(test)(range(10)) test(range(10))
六:裝飾器應用案例:
裝飾器功能:函數超時則終止
# -*- coding: utf-8 -*- from threading import Thread import time class TimeoutException(Exception): pass ThreadStop = Thread._Thread__stop#獲取私有函數 def timelimited(timeout): def decorator(function): def decorator2(*args,**kwargs): class TimeLimited(Thread): def __init__(self,_error= None,): Thread.__init__(self) self._error = _error def run(self): try: self.result = function(*args,**kwargs) except Exception,e: self._error =e def _stop(self): if self.isAlive(): ThreadStop(self) t = TimeLimited() t.start() t.join(timeout) if isinstance(t._error,TimeoutException): t._stop() raise TimeoutException('timeout for %s' % (repr(function))) if t.isAlive(): t._stop() raise TimeoutException('timeout for %s' % (repr(function))) if t._error is None: return t.result return decorator2 return decorator @timelimited(2) def fn_1(secs): time.sleep(secs) return 'Finished' if __name__ == "__main__": print fn_1(4)