国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

分析Python中設計模式之Decorator裝飾器模式的要點

來源:懂視網 責編:小采 時間:2020-11-27 14:35:34
文檔

分析Python中設計模式之Decorator裝飾器模式的要點

分析Python中設計模式之Decorator裝飾器模式的要點:先給出一個四人團對Decorator mode的定義:動態地給一個對象添加一些額外的職責。 再來說說這個模式的好處:認證,權限檢查,記日志,檢查參數,加鎖,等等等等,這些功能和系統業務無關,但又是系統所必須的,說的更明白一點,就是面向方面的編程(AOP)
推薦度:
導讀分析Python中設計模式之Decorator裝飾器模式的要點:先給出一個四人團對Decorator mode的定義:動態地給一個對象添加一些額外的職責。 再來說說這個模式的好處:認證,權限檢查,記日志,檢查參數,加鎖,等等等等,這些功能和系統業務無關,但又是系統所必須的,說的更明白一點,就是面向方面的編程(AOP)

先給出一個四人團對Decorator mode的定義:動態地給一個對象添加一些額外的職責。
再來說說這個模式的好處:認證,權限檢查,記日志,檢查參數,加鎖,等等等等,這些功能和系統業務無關,但又是系統所必須的,說的更明白一點,就是面向方面的編程(AOP)。
在Python中Decorator mode可以按照像其它編程語言如C++, Java等的樣子來實現,但是Python在應用裝飾概念方面的能力上遠不止于此,Python提供了一個語法和一個編程特性來加強這方面的功能。Python提供的語法就是裝飾器語法(decorator),如下:

@aoo
def foo(): pass
def aoo(fn):
 return fn

裝飾模式強調動態地給對象添加額外的功能。 Python內置了很多對裝飾器的支持,因此在Python中使用裝飾模式是非常容易的,下面是一個典型的例子,給函數增加日志功能:

import functools
def log_wrapper(fun):
 @functools.wraps(fun)
 def wrapper(*args, **kwargs):
 print '在函數執行前加日志'
 ret = fun(*args, **kwargs)
 print '在函數執行后家日志'
 return ret
 return wrapper


@log_wrapper
def test():
 print 'Hello, 世界'

functools.wraps是Python標準庫提供的一個特殊的裝飾器,用來解決裝飾器帶來的一些常規問題,如函數名稱、doc等的不一致問題。@是Python針對裝飾器提供的一個語法糖,上面的@log_wrapper相當于wrap_test = log_rapper(test),用@后,這個步驟由解釋器代勞了。

裝飾器是Python編程必須掌握的一項技能,在編碼過程中經常會用到。

這里只是一個普通的內嵌函數

def foo(x):
 y = x
 def foo1 ():
 a = 1
 return a
 return foo1

而下面boo則是一個閉包

def aoo(a, b):
 c = a
 def boo (x):
 x = b + 1
 return x
 return boo

boo的特殊性在于引用了外部變量b,當aoo返回后,只要返回值(boo)一直存在,則對b的引用就會一直存在。
上面的知識可能需要花些時間消化,如果你覺得已經掌握了這些知識,下面就回歸正題,看看這些語言特性是怎樣來實現Python中裝飾的概念的。
還是讓我們先看一個簡單的例子,然后逐步深入。這個例子就是加鎖,怎樣實現加鎖的功能?
具體需求是這樣的:我有一個對象,實現了某些功能并提供了一些接口供其它模塊調用,這個對象是運行在并發的環境中的,因此我需要對接口的調用進行同步,第一版的代碼如下:

class Foo(object):
 def __init__(self, …):
 self.lock = threading.Lock()
 def interface1(self, …):
 self.lock.acquire()
 try:
 do something
 finally:
 self.lock.release()
 def interface2(self, …):
 same as interface1()
 …

這版代碼的問題很明顯,那就是每個接口函數都有相同的加鎖/解鎖代碼,重復的代碼帶來的是更多的鍵入,更多的閱讀,更多的維護,以及更多的修改,最主要的是,程序員本應集中在業務上的的精力被分散了,而且請注意,真正的業務代碼在距離函數定義2次縮進處開始,即使你的顯示器是寬屏,這也會帶來一些閱讀上的困難。
你直覺的認為,可以把這些代碼收進一個函數中,以達到復用的目的,但是請注意,這些代碼不是一個完整同一的代碼塊,而是在中間嵌入了業務代碼。
現在我們用裝飾器語法來改進這部分代碼,得到第2版代碼:

def sync(func):
 def wrapper(*args, **kv):
 self = args[0]
 self.lock.acquire()
 try:
 return func(*args, **kv)
 finally:
 self.lock.release()
 return wrapper
class Foo(object):
 def __init__(self, …):
 self.lock = threading.Lock()
 @sync
 def interface1(self, …):
 do something
 @sync
 def interface2(self, …):
 do something
 …

一個裝飾器函數的第一個參數是所要裝飾的那個函數對象,而且裝飾器函數必須返回一個函數對象。如sync函數,當其裝飾interface1時,參數func的值就是interface1,返回值是wrapper,但類Foo實例的interface1被調用時,實際調用的是wrapper函數,在wrapper函數體中間接調用實際的interface1;當interface2被調用時,也調用的是wrapper函數,不過由于在裝飾時func已經變成interface2,所以會間接地調用到實際的interface2函數。
使用裝飾器語法的好處:
代碼量大大的減少了,更少的代碼意味著更少的維護,更少的閱讀,更少的鍵入,好處不一而足(可復用,可維護)
用戶基本上將絕大部分精力放在了業務代碼上,而且少了加減鎖的代碼,可讀性也提高了
缺點:
業務對象Foo中有一個非業務數據成員lock,很礙眼;
相當程度的耦合,wrapper的第一個參數必須是對象本身,而且被裝飾的對象中必須有一個lock對象存在,這給客戶對象添加了限制,使用起來不是很舒服。
我們可以更進一步想一想:
lock對象必須要放在Foo中嗎?
為每個接口函數都鍵入@sync還是很煩人的重復性人工工作,如果漏添加一個,還是會造成莫名其妙的運行時錯誤,為什么不集中處理呢?
為了解決上述的缺點,第3版代碼如下:

class DecorateClass(object):
 def decorate(self):
 for name, fn in self.iter():
 if not self.filter(name, fn):
 continue
 self.operate(name, fn)
class LockerDecorator(DecorateClass):
 def __init__(self, obj, lock = threading.RLock()):
 self.obj = obj
 self.lock = lock
 def iter(self):
 return [(name, getattr(self.obj, name)) for name in dir(self.obj)]
 def filter(self, name, fn):
 if not name.startswith('_') and callable(fn):
 return True
 else:
 return False
 def operate(self, name, fn):
 def locker(*args, **kv):
 self.lock.acquire()
 try:
 return fn(*args, **kv)
 finally:
 self.lock.release()
 setattr(self.obj, name, locker)
class Foo(object):
 def __init__(self, …):
 …
 LockerDecorator(self).decorate()
 def interface1(self, …):
 do something
 def interface2(self, …):
 do something
 …

對對象的功能裝飾是一個更一般的功能,不僅限于為接口加鎖,我用2個類來完成這一功能,DecorateClass是一個基類,只定義了遍歷并應用裝飾功能的算法代碼(template method),LockerDecorator實現了為對象加鎖的功能,其中iter是迭代器,定義了怎樣遍歷對象中的成員(包括數據成員和成員函數),filter是過濾器,定義了符合什么規則的成員才能成為一個接口,operate是執行函數,具體實施了為對象接口加鎖的功能。
而在業務類Foo的__init__函數中,只需要在最后添加一行代碼:LockerDecorator(self).decorate(),就可以完成為對象加鎖的功能。
如果你的對象提供的接口有特殊性,完全可以通過直接改寫filter或者繼承LockerDecorator并覆蓋filter的方式來實現;此外,如果要使用其他的裝飾功能,可以寫一個繼承自DecorateClass的類,并實現iter,filter和operate三個函數即可。

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

分析Python中設計模式之Decorator裝飾器模式的要點

分析Python中設計模式之Decorator裝飾器模式的要點:先給出一個四人團對Decorator mode的定義:動態地給一個對象添加一些額外的職責。 再來說說這個模式的好處:認證,權限檢查,記日志,檢查參數,加鎖,等等等等,這些功能和系統業務無關,但又是系統所必須的,說的更明白一點,就是面向方面的編程(AOP)
推薦度:
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 337p日本欧洲亚洲大胆精品 | 在线观看欧美 | 另类一区二区 | 日韩美女一区二区三区 | 亚洲精美视频 | 91原创在线 | 成人一级视频 | 国产一区91 | 午夜啪啪网 | 国产精品亚洲色图 | 激情综合亚洲欧美日韩 | 欧美成人一区二区三区在线视频 | 国产成人在线精品 | 欧美日韩精品一区二区在线播放 | 午夜视频国产 | 日韩在线视频播放 | 国产91成人精品亚洲精品 | 欧美精品在线观看视频 | 国产精品免费观看网站 | 韩日一区二区三区 | 免费观看欧美一区二区三区 | 欧美高清免费 | 国产一区精品在线观看 | 日韩欧美在线综合网 | 国产高清美女一级毛片久久 | 国产精品亚洲专区在线观看 | 国产精品免费 | xxx色| 欧美综合在线观看 | 欧美地区一二三 | 亚洲久草| 欧美日韩国产一区 | 韩国精品一区二区久久 | 日韩在线一区二区 | 成人特黄午夜性a一级毛片 成人国产一区二区三区精品 | 欧美一区二区三区香蕉视 | 亚洲色图欧美激情 | 免费在线观看一区二区 | 亚洲欧美专区 | 亚洲综合欧美日韩 | 五月天丁香网 |