http://blog.csdn.net/wklken/article/details/8118942
-----------------------------------------------
想找個地方快樂的coding,貌似不是一件容易的事情。
一時衝動,不過後路已斷,做自己想做的事情,總要付出一些代價的,堅持吧,只能。
吐槽下,本周各種事情,搞得如越級打怪般艱難。周六,去三小時,回來三小時,大敗而歸,但是還是學到不少東西。
差距還是有的,雖然自信可以在最短時間補上,但是,需要成本。
總之,貌似時機不對,哎以上廢話,進入正題
上周六碰到了,一周忙碌,今天稍微理下,待補全,資料主要來源於書籍,網路&self.coding()。有任何問題,請指正哈 基本概念
具體概念自己google
裝飾器是一個很著名的設計模式,經常被用於有切面需求的情境,較為經典的有插入日誌、效能測試、交易處理, Web許可權校正, Cache等。
很有名的例子,就是咖啡,加糖的咖啡,加牛奶的咖啡。本質上,還是咖啡,只是在原有的東西上,做了“裝飾”,使之附加一些功能或特性。
例如記錄日誌,需要對某些函數進行記錄
笨的辦法,每個函數加入代碼,如果代碼變了,就悲催了
裝飾器的辦法,定義一個專門日誌記錄的裝飾器,對需要的函數進行裝飾,搞定 優點
抽離出大量函數中與函數功能本身無關的雷同代碼並繼續重用
即,可以將函數“修飾”為完全不同的行為,可以有效將商務邏輯正交分解,如用於將許可權和身分識別驗證從業務中獨立出來
概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能 Python中的裝飾器
在Python中,裝飾器實現是十分方便的
原因是:函數可以被扔來扔去。
函數作為一個對象:
A.可以被賦值給其他變數,可以作為傳回值B.可以被定義在另外一個函數內
def:
裝飾器是一個函數,一個用來封裝函數的函數,裝飾器在函數申明完成的時候被調用,調用之後返回一個修改之後的函數對象,將其重新賦值原來的標識符,並永久喪失對原始函數對象的訪問(申明的函數被換成一個被裝飾器裝飾過後的函數)
當我們對某個方法應用了裝飾方法後, 其實就改變了被裝飾函數名稱所引用的函數代碼塊進入點,使其重新指向了由裝飾方法所返回的函數進入點。
由此我們可以用decorator改變某個原有函數的功能,添加各種操作,或者完全改變原有實現 分類:
裝飾器分為無參數decorator,有參數decorator
* 無參數decorator產生一個新的裝飾器函數* 有參decorator有參裝飾,裝飾函數先處理參數,再產生一個新的裝飾器函數,然後對函數進行裝飾
裝飾器有參/無參,函數有參/無參,組合共4種 具體定義:
decorator方法
A.把要裝飾的方法作為輸入參數,
B.在函數體內可以進行任意的操作(可以想象其中蘊含的威力強大,會有很多應用情境),
C.只要確保最後返回一個可執行檔函數即可(可以是原來的輸入參數函數, 或者是一個新函數) 無參數裝飾器 – 封裝無參數函數
不需要針對參數進行處理和最佳化
def decorator(func): print "hello" return func@decoratordef foo(): passfoo()
foo()等價於:
foo = decorator(foo)foo()
無參數裝飾器 – 封裝帶參數函數
def decorator_func_args(func): def handle_args(*args, **kwargs): #處理傳入函數的參數 print "begin" func(*args, **kwargs) #函數調用 print "end" return handle_args@decorator_func_argsdef foo2(a, b=2): print a, bfoo2(1)
foo2(1)等價於
foo2 = decorator_func_args(foo2)foo2(1)
帶參數裝飾器 – 封裝無參數函數
def decorator_with_params(arg_of_decorator):#這裡是裝飾器的參數 print arg_of_decorator #最終被返回的函數 def newDecorator(func): print func return func return newDecorator@decorator_with_params("deco_args")def foo3(): passfoo3()
與前面的不同在於:比上一層多了一層封裝,先傳遞參數,再傳遞函數名
第一個函數decomaker是裝飾函數,它的參數是用來加強“加強裝飾”的。由於此函數並非被裝飾的函數對象,所以在內部必須至少建立一個接受被裝飾函數的函數,然後返回這個對象(實際上此時foo3= decorator_with_params(arg_of_decorator)(foo3)) 帶參數裝飾器– 封裝帶參數函數
def decorator_whith_params_and_func_args(arg_of_decorator): def handle_func(func): def handle_args(*args, **kwargs): print "begin" func(*args, **kwargs) print "end" print arg_of_decorator, func, args,kwargs return handle_args return handle_func@decorator_whith_params_and_func_args("123")def foo4(a, b=2): print "Content"foo4(1, b=3)
內建裝飾器
內建的裝飾器有三個:staticmethod,classmethod, property
class A(): @staticmethod def test_static(): print "static" def test_normal(self): print "normal" @classmethod def test_class(cls): print "class", clsa = A()A.test_static()a.test_static()a.test_normal()a.test_class()
結果:
staticstaticnormalclass __main__.A
A.test_static
staticmethod 類中定義的執行個體方法變成靜態方法
基本上和一個全域函數差不多(不需要傳入self,只有一般的參數),只不過可以通過類或類的執行個體對象來調用,不會隱式地傳入任何參數。
類似於靜態語言中的靜態方法
B.test_normal
普通對象方法:普通對象方法至少需要一個self參數,代表類對象執行個體
C.test_class
類中定義的執行個體方法變成類方法
classmethod需要傳入類對象,可以通過執行個體和類對象進行調用。
是和一個class相關的方法,可以通過類或類執行個體調用,並將該class對象(不是class的執行個體對象)隱式地當作第一個參數傳入。
就這種方法可能會 比較奇怪一點,不過只要你搞清楚了python裡class也是個真實地存在於記憶體中的對象,而不是靜態語言中只存在於編譯期間的類型,就好辦了。正常的方法就是和一個類的執行個體對象相關的方法,通過類執行個體對象進行調用,並將該執行個體對象隱式地作為第一個參數傳入,這個也和其它語言比較像。
D.區別
staticmethod,classmethod相當於全域方法,一般用在抽象類別或父類中。一般與具體的類無關。
類方法需要額外的類變數cls,當有子類繼承時,調用類方法傳入的類變數cls是子類,而不是父類。
類方法和靜態方法都可以通過類對象和類的執行個體對象訪問
定義方式,傳入的參數,調用方式都不相同。
E.property
對類屬性的操作,類似於java中定義getter/setter
class B(): def __init__(self): self.__prop = 1 @property def prop(self): print "call get" return self.__prop @prop.setter def prop(self, value): print "call set" self.__prop = value @prop.deleter def prop(self): print "call del" del self.__prop
其他
A.裝飾器的順序很重要,需要注意
@A@B@Cdef f ():
等價於
f = A(B(C(f)))
B.decorator的作用對象可以是模組層級的方法或者類方法
C.functools模組提供了兩個裝飾器。這個模組是Python 2.5後新增的。
functools.wraps(func)total_ordering(cls)這個具體自己去看吧,後續用到了再補充 一個簡單例子
通過一個變數,控制調用函數時是否統計時間
#!/usr/bin/env python# -*- coding:utf-8 -*-#@author: wklken@yeah.net#@version: a test of decorator#@date: 20121027#@desc: just a testimport loggingfrom time import timelogger = logging.getLogger()logger.setLevel(logging.DEBUG)is_debug = Truedef count_time(is_debug): def handle_func(func): def handle_args(*args, **kwargs): if is_debug: begin = time() func(*args, **kwargs) logging.debug( "[" + func.__name__ + "] -> " + str(time() - begin) ) else: func(*args, **kwargs) return handle_args return handle_funcdef pr(): for i in range(1,1000000): i = i * 2 print "hello world"def test(): pr()@count_time(is_debug)def test2(): pr()@count_time(False)def test3(): pr()if __name__ == "__main__": test() test2() test3()
結果:
hello worldhello worldDEBUG:root:[test2] -> 0.0748538970947hello world
The end!
wklken
Gighub: https://github.com/wklken
Blog: http://wklken.sinaapp.com/
2012-10-27
轉載請註明出處,謝謝!