啥是裝飾器?python
python裝飾器本質上就是一個函數,它可讓其餘函數在不須要作任何代碼變更(被裝飾的函數調用方式 返回值等不改變)的前提下增長額外的功能,裝飾器的返回值也是一個函數對象(函數的指針)web
裝飾器做用 是對於咱們已經寫好的程序,能夠抽離出一些雷同的代碼組建多個特定功能的裝飾器,這樣咱們就能夠針對不一樣的需求去使用特定的裝飾器,這時由於源碼去除了大量泛化的內容而使得源碼具備更加清晰的邏輯。閉包
裝飾器的屬性:app
實質: 是一個函數函數
參數:是你要裝飾的函數名(並非函數調用)性能
返回:是裝飾完的函數名(也非函數調用)測試
做用:爲已經存在的對象添加額外的功能spa
特色:不須要對對象作任何的代碼上的變更指針
多個裝飾器的執行順序:是從近到遠依次執行。日誌
裝飾器的應用場景:
插入日誌、性能測試、事務處理、權限校驗、統計函數的執行時間等
在看裝飾器以前,咱們先來搞清楚什麼是閉包函數:
若是內部函數裏引用了外部函數裏定義的對象(甚至是外層以外,但不是全局變量),那麼此時內部函數就被稱爲閉包函數。閉包函數所引用的外部定義的變量被叫作自由變量。閉包從語法上看很是簡單,可是卻有強大的做用。閉包能夠將其本身的代碼和做用域以及外部函數的做用結合在一塊兒
總結:什麼函數能夠被稱爲閉包函數呢?主要是知足兩點:函數內部定義的函數;引用了外部變量但非全局變量。
裝飾器的代碼案例
#!/usr/bin/env python3 # -*- coding:utf-8 -*- username, password = 'root', 'root123' def autoLogin(loginType): print('loginType:', loginType) def outWrapp(func): def wrapp(*args, **kwargs): inName = input('username:') inPasswd = input('password:') if inName == username and inPasswd == password : print("login sucess")
else:
print("Invalid login username or password error") return return func(*args, **kwargs) return wrapp return outWrapp @autoLogin(loginType='web') def webLogin(): print('in webLogin funtion'.center(50, '*')) return "webLogin function" @autoLogin(loginType='local') def localLogin(): print('in localLogin funciton'.center(50, '=')) return "localLogin function" webResult = webLogin() print(webResult) localResult = localLogin() print(localResult)
上面的案例 看似完美解決了在不改變原來函數代碼的狀況下新增了一些功能,也沒有改變函數的調用方式。 可是函數的函數名屬性卻被咱們改變了, 怎麼看咱們改變了函數的函數名屬性呢, 咱們能夠打印一下函數的屬性名就知道了 print(webLogin.__name__) 結果返回的不是 webLogin,而是wrapp。這是爲何呢? 其實函數名也是一個變量,而裝飾器裝飾函數實際上是把原來的函數進行包裝返回一個閉包函數給原來的變量名。就至關於 def func1(): pass fun=func1 同樣 fun.__name__ 返回的就是func1. 那這樣不是也相對於改變被裝飾的函數了嘛, 有沒有一種方法能夠解決這個問題呢? 固然有方法, 否則裝飾器的特色就變成了缺點。方法就是應用一個包的函數:functools.wraps()
#!/usr/bin/env python3 # -*- coding:utf-8 -*- from functools import wraps def decoratorFun(func): @wraps(func) def innerFunc(): print('in inerFunc') return func() return innerFunc @decoratorFun def outfun(): print('in outfun') print(outfun.__name__) #output: outfun
這樣個人裝飾器纔算完美。