最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

分析Python中設(shè)計(jì)模式之Decorator裝飾器模式的要點(diǎn)

 更新時(shí)間:2016年03月02日 12:02:50   作者:tqsummer  
這篇文章主要介紹了Python中設(shè)計(jì)模式之Decorator裝飾器模式模式,文中詳細(xì)地講解了裝飾對(duì)象的相關(guān)加鎖問(wèn)題,需要的朋友可以參考下

先給出一個(gè)四人團(tuán)對(duì)Decorator mode的定義:動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。
再來(lái)說(shuō)說(shuō)這個(gè)模式的好處:認(rèn)證,權(quán)限檢查,記日志,檢查參數(shù),加鎖,等等等等,這些功能和系統(tǒng)業(yè)務(wù)無(wú)關(guān),但又是系統(tǒng)所必須的,說(shuō)的更明白一點(diǎn),就是面向方面的編程(AOP)。
在Python中Decorator mode可以按照像其它編程語(yǔ)言如C++, Java等的樣子來(lái)實(shí)現(xiàn),但是Python在應(yīng)用裝飾概念方面的能力上遠(yuǎn)不止于此,Python提供了一個(gè)語(yǔ)法和一個(gè)編程特性來(lái)加強(qiáng)這方面的功能。Python提供的語(yǔ)法就是裝飾器語(yǔ)法(decorator),如下:

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

裝飾模式強(qiáng)調(diào)動(dòng)態(tài)地給對(duì)象添加額外的功能。 Python內(nèi)置了很多對(duì)裝飾器的支持,因此在Python中使用裝飾模式是非常容易的,下面是一個(gè)典型的例子,給函數(shù)增加日志功能:

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


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

functools.wraps是Python標(biāo)準(zhǔn)庫(kù)提供的一個(gè)特殊的裝飾器,用來(lái)解決裝飾器帶來(lái)的一些常規(guī)問(wèn)題,如函數(shù)名稱(chēng)、doc等的不一致問(wèn)題。@是Python針對(duì)裝飾器提供的一個(gè)語(yǔ)法糖,上面的@log_wrapper相當(dāng)于wrap_test = log_rapper(test),用@后,這個(gè)步驟由解釋器代勞了。

裝飾器是Python編程必須掌握的一項(xiàng)技能,在編碼過(guò)程中經(jīng)常會(huì)用到。

這里只是一個(gè)普通的內(nèi)嵌函數(shù)

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

而下面boo則是一個(gè)閉包

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

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

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()
  …

這版代碼的問(wèn)題很明顯,那就是每個(gè)接口函數(shù)都有相同的加鎖/解鎖代碼,重復(fù)的代碼帶來(lái)的是更多的鍵入,更多的閱讀,更多的維護(hù),以及更多的修改,最主要的是,程序員本應(yīng)集中在業(yè)務(wù)上的的精力被分散了,而且請(qǐng)注意,真正的業(yè)務(wù)代碼在距離函數(shù)定義2次縮進(jìn)處開(kāi)始,即使你的顯示器是寬屏,這也會(huì)帶來(lái)一些閱讀上的困難。
你直覺(jué)的認(rèn)為,可以把這些代碼收進(jìn)一個(gè)函數(shù)中,以達(dá)到復(fù)用的目的,但是請(qǐng)注意,這些代碼不是一個(gè)完整同一的代碼塊,而是在中間嵌入了業(yè)務(wù)代碼。
現(xiàn)在我們用裝飾器語(yǔ)法來(lái)改進(jìn)這部分代碼,得到第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
  …

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

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

相關(guān)文章

  • 基于python的多進(jìn)程共享變量正確打開(kāi)方式

    基于python的多進(jìn)程共享變量正確打開(kāi)方式

    下面小編就為大家分享一篇基于python的多進(jìn)程共享變量正確打開(kāi)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • Python執(zhí)行流程控制詳情

    Python執(zhí)行流程控制詳情

    這篇文章主要介紹了Python執(zhí)行流程控制,流程控制即控制流程,具體指控制程序的執(zhí)行流程,而程序的執(zhí)行流程分為三種結(jié)構(gòu):順序結(jié)構(gòu)、分支結(jié)構(gòu)、循環(huán)結(jié)構(gòu),下文詳細(xì)介紹需要的小伙伴可以參考一下
    2022-04-04
  • pyqt5 刪除layout中的所有widget方法

    pyqt5 刪除layout中的所有widget方法

    今天小編就為大家分享一篇pyqt5 刪除layout中的所有widget方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06
  • Python2.x版本中cmp()方法的使用教程

    Python2.x版本中cmp()方法的使用教程

    這篇文章主要介紹了Python2.x版本中cmp()方法的使用教程,在Python3.x版本中該方法不再被內(nèi)置,需要的朋友可以參考下
    2015-05-05
  • matplotlib實(shí)現(xiàn)熱成像圖colorbar和極坐標(biāo)圖的方法

    matplotlib實(shí)現(xiàn)熱成像圖colorbar和極坐標(biāo)圖的方法

    今天小編就為大家分享一篇matplotlib實(shí)現(xiàn)熱成像圖colorbar和極坐標(biāo)圖的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • Pandas數(shù)據(jù)處理加速技巧匯總

    Pandas數(shù)據(jù)處理加速技巧匯總

    Pandas?處理數(shù)據(jù)的效率還是很優(yōu)秀的,相對(duì)于大規(guī)模的數(shù)據(jù)集只要掌握好正確的方法,就能讓在數(shù)據(jù)處理時(shí)間上節(jié)省很多很多的時(shí)間。本文為大家匯總了一些Pandas數(shù)據(jù)處理加速技巧,需要的可以參考一下
    2022-04-04
  • python+rsync精確同步指定格式文件

    python+rsync精確同步指定格式文件

    這篇文章主要為大家詳細(xì)介紹了python+rsync精確同步指定格式文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • python文件讀寫(xiě)操作與linux shell變量命令交互執(zhí)行的方法

    python文件讀寫(xiě)操作與linux shell變量命令交互執(zhí)行的方法

    這篇文章主要介紹了python文件讀寫(xiě)操作與linux shell變量命令交互執(zhí)行的方法,涉及對(duì)文件操作及Linux shell交互的技巧,需要的朋友可以參考下
    2015-01-01
  • python批量檢查兩個(gè)對(duì)應(yīng)的txt文件的行數(shù)是否一致的實(shí)例代碼

    python批量檢查兩個(gè)對(duì)應(yīng)的txt文件的行數(shù)是否一致的實(shí)例代碼

    這篇文章主要介紹了python批量檢查兩個(gè)對(duì)應(yīng)的txt文件的行數(shù)是否一致,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • python如何查看安裝了的模塊

    python如何查看安裝了的模塊

    在本篇文章里小編給大家分享的是一篇關(guān)于python查看安裝了的模塊的方法,需要的朋友們可以學(xué)習(xí)下。
    2020-06-06

最新評(píng)論

宁都县| 镇安县| 保山市| 明星| 横峰县| 宣武区| 建湖县| 望奎县| 嘉禾县| 永和县| 宜宾市| 虎林市| 济南市| 新乡县| 萨迦县| 水富县| 通辽市| 津南区| 怀化市| 含山县| 柳林县| 安顺市| 嘉禾县| 临猗县| 麟游县| 临泉县| 临湘市| 鄂伦春自治旗| 闽清县| 珲春市| 湟源县| 甘孜县| 夏河县| 永丰县| 枣阳市| 波密县| 新晃| 英山县| 隆德县| 竹溪县| 龙陵县|