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

Python類裝飾器實現(xiàn)方法詳解

 更新時間:2018年12月21日 12:05:26   作者:KLeonard  
這篇文章主要介紹了Python類裝飾器實現(xiàn)方法,結(jié)合實例形式較為詳細(xì)的分析了Python類裝飾器的相關(guān)概念、原理、實現(xiàn)方法與使用技巧,需要的朋友可以參考下

本文實例講述了Python類裝飾器。分享給大家供大家參考,具體如下:

編寫類裝飾器

類裝飾器類似于函數(shù)裝飾器的概念,但它應(yīng)用于類,它們可以用于管理類自身,或者用來攔截實例創(chuàng)建調(diào)用以管理實例。

單體類

由于類裝飾器可以攔截實例創(chuàng)建調(diào)用,所以它們可以用來管理一個類的所有實例,或者擴(kuò)展這些實例的接口。

下面的類裝飾器實現(xiàn)了傳統(tǒng)的單體編碼模式,即最多只有一個類的一個實例存在。

instances = {} # 全局變量,管理實例
def getInstance(aClass, *args):
  if aClass not in instances:
    instances[aClass] = aClass(*args)
  return instances[aClass]   #每一個類只能存在一個實例
def singleton(aClass):
  def onCall(*args):
    return getInstance(aClass,*args)
  return onCall
為了使用它,裝飾用來強(qiáng)化單體模型的類:
@singleton    # Person = singleton(Person)
class Person:
  def __init__(self,name,hours,rate):
    self.name = name
    self.hours = hours
    self.rate = rate
  def pay(self):
    return self.hours * self.rate
@singleton    # Spam = singleton(Spam)
class Spam:
  def __init__(self,val):
    self.attr = val
bob = Person('Bob',40,10)
print(bob.name,bob.pay())
sue = Person('Sue',50,20)
print(sue.name,sue.pay())
X = Spam(42)
Y = Spam(99)
print(X.attr,Y.attr)

現(xiàn)在,當(dāng)Person或Spam類稍后用來創(chuàng)建一個實例的時候,裝飾器提供的包裝邏輯層把實例構(gòu)建調(diào)用指向了onCall,它反過來調(diào)用getInstance,以針對每個類管理并分享一個單個實例,而不管進(jìn)行了多少次構(gòu)建調(diào)用。

程序輸出如下:

Bob 400
Bob 400
42 42

在這里,我們使用全局的字典instances來保存實例,還有一個更好的解決方案就是使用Python3中的nonlocal關(guān)鍵字,它可以為每個類提供一個封閉的作用域,如下:

def singleton(aClass):
 instance = None
 def onCall(*args):
 nonlocal instance
 if instance == None:
  instance = aClass(*args)
 return instance
 return onCall

當(dāng)然,我們也可以用類來編寫這個裝飾器——如下代碼對每個類使用一個實例,而不是使用一個封閉作用域或全局表:

class singleton:
 def __init__(self,aClass):
 self.aClass = aClass
 self.instance = None
 def __call__(self,*args):
 if self.instance == None:
  self.instance = self.aClass(*args)
 return self.instance

跟蹤對象接口

類裝飾器的另一個常用場景是每個產(chǎn)生實例的接口。類裝飾器基本上可以在實例上安裝一個包裝器邏輯層,來以某種方式管理其對接口的訪問。

前面,我們知道可以用__getattr__運(yùn)算符重載方法作為包裝嵌入到實例的整個對象接口的方法,以便實現(xiàn)委托編碼模式。__getattr__用于攔截未定義的屬性名的訪問。如下例子所示:

class Wrapper:
 def __init__(self,obj):
 self.wrapped = obj
 def __getattr__(self,attrname):
 print('Trace:',attrname)
 return getattr(self.wrapped,attrname)
>>> x = Wrapper([1,2,3])
>>> x.append(4)
Trace: append
>>> x.wrapped
[1, 2, 3, 4]
>>>
>>> x = Wrapper({'a':1,'b':2})
>>> list(x.keys())
Trace: keys
['b', 'a']

在這段代碼中,Wrapper類攔截了對任何包裝對象的屬性的訪問,打印出一條跟蹤信息,并且使用內(nèi)置函數(shù)getattr來終止對包裝對象的請求。

類裝飾器為編寫這種__getattr__技術(shù)來包裝一個完整接口提供了一個替代的、方便的方法。如下:

def Tracer(aClass):
  class Wrapper:
    def __init__(self,*args,**kargs):
      self.fetches = 0
      self.wrapped = aClass(*args,**kargs)
    def __getattr__(self,attrname):
      print('Trace:'+attrname)
      self.fetches += 1
      return getattr(self.wrapped,attrname)
  return Wrapper
@Tracer
class Spam:
  def display(self):
    print('Spam!'*8)
@Tracer
class Person:
  def __init__(self,name,hours,rate):
    self.name = name
    self.hours = hours
    self.rate = rate
  def pay(self):
    return self.hours * self.rate
food = Spam()
food.display()
print([food.fetches])
bob = Person('Bob',40,50)
print(bob.name)
print(bob.pay())
print('')
sue = Person('Sue',rate=100,hours = 60)
print(sue.name)
print(sue.pay())
print(bob.name)
print(bob.pay())
print([bob.fetches,sue.fetches])

通過攔截實例創(chuàng)建調(diào)用,這里的類裝飾器允許我們跟蹤整個對象接口,例如,對其任何屬性的訪問。

Spam和Person類的實例上的屬性獲取都會調(diào)用Wrapper類中的__getattr__邏輯,由于food和bob確實都是Wrapper的實例,得益于裝飾器的實例創(chuàng)建調(diào)用重定向,輸出如下:

Trace:display
Spam!Spam!Spam!Spam!Spam!Spam!Spam!Spam!
[1]
Trace:name
Bob
Trace:pay
2000
Trace:name
Sue
Trace:pay
6000
Trace:name
Bob
Trace:pay
2000
[4, 2]

示例:實現(xiàn)私有屬性

如下的類裝飾器實現(xiàn)了一個用于類實例屬性的Private聲明,也就是說,屬性存儲在一個實例上,或者從其一個類繼承而來。不接受從裝飾的類的外部對這樣的屬性的獲取和修改訪問,但是,仍然允許類自身在其方法中自由地訪問那些名稱。類似于Java中的private屬性。

traceMe = False
def trace(*args):
  if traceMe:
    print('['+ ' '.join(map(str,args))+ ']')
def Private(*privates):
  def onDecorator(aClass):
    class onInstance:
      def __init__(self,*args,**kargs):
        self.wrapped = aClass(*args,**kargs)
      def __getattr__(self,attr):
        trace('get:',attr)
        if attr in privates:
          raise TypeError('private attribute fetch:'+attr)
        else:
          return getattr(self.wrapped,attr)
      def __setattr__(self,attr,value):
        trace('set:',attr,value)
        if attr == 'wrapped': # 這里捕捉對wrapped的賦值
          self.__dict__[attr] = value
        elif attr in privates:
          raise TypeError('private attribute change:'+attr)
        else: # 這里捕捉對wrapped.attr的賦值
          setattr(self.wrapped,attr,value)
    return onInstance
  return onDecorator
if __name__ == '__main__':
  traceMe = True
  @Private('data','size')
  class Doubler:
    def __init__(self,label,start):
      self.label = label
      self.data = start
    def size(self):
      return len(self.data)
    def double(self):
      for i in range(self.size()):
        self.data[i] = self.data[i] * 2
    def display(self):
      print('%s => %s'%(self.label,self.data))
  X = Doubler('X is',[1,2,3])
  Y = Doubler('Y is',[-10,-20,-30])
  print(X.label)
  X.display()
  X.double()
  X.display()
  print(Y.label)
  Y.display()
  Y.double()
  Y.label = 'Spam'
  Y.display()
  # 這些訪問都會引發(fā)異常
  """
  print(X.size())
  print(X.data)
  X.data = [1,1,1]
  X.size = lambda S:0
  print(Y.data)
  print(Y.size())

這個示例運(yùn)用了裝飾器參數(shù)等語法,稍微有些復(fù)雜,運(yùn)行結(jié)果如下:

[set: wrapped <__main__.Doubler object at 0x03421F10>]
[set: wrapped <__main__.Doubler object at 0x031B7470>]
[get: label]
X is
[get: display]
X is => [1, 2, 3]
[get: double]
[get: display]
X is => [2, 4, 6]
[get: label]
Y is
[get: display]
Y is => [-10, -20, -30]
[get: double]
[set: label Spam]
[get: display]
Spam => [-20, -40, -60]

更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python Socket編程技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》及《Python入門與進(jìn)階經(jīng)典教程

希望本文所述對大家Python程序設(shè)計有所幫助。

相關(guān)文章

  • Python高階函數(shù)、常用內(nèi)置函數(shù)用法實例分析

    Python高階函數(shù)、常用內(nèi)置函數(shù)用法實例分析

    這篇文章主要介紹了Python高階函數(shù)、常用內(nèi)置函數(shù)用法,結(jié)合實例形式分析了Python高階函數(shù)與常用內(nèi)置函數(shù)相關(guān)功能、原理、使用技巧與操作注意事項,需要的朋友可以參考下
    2019-12-12
  • Python 實現(xiàn)字符串中指定位置插入一個字符

    Python 實現(xiàn)字符串中指定位置插入一個字符

    下面小編就為大家分享一篇Python 實現(xiàn)字符串中指定位置插入一個字符,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • python+Splinter實現(xiàn)12306搶票功能

    python+Splinter實現(xiàn)12306搶票功能

    這篇文章主要為大家詳細(xì)介紹了python+Splinter實現(xiàn)12306搶票功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • Python GUI框架中的PyQt詳解

    Python GUI框架中的PyQt詳解

    PyQt是Python語言中最強(qiáng)大且廣泛應(yīng)用的GUI框架之一,基于Qt庫的Python綁定實現(xiàn),本文將深入解析PyQt的核心模塊,并通過代碼示例展示其應(yīng)用場景,感興趣的朋友一起看看吧
    2025-03-03
  • python進(jìn)程間通信Queue工作過程詳解

    python進(jìn)程間通信Queue工作過程詳解

    這篇文章主要介紹了python進(jìn)程間通信Queue工作過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • python實現(xiàn)基于SVM手寫數(shù)字識別功能

    python實現(xiàn)基于SVM手寫數(shù)字識別功能

    這篇文章主要為大家詳細(xì)介紹了python實現(xiàn)基于SVM手寫數(shù)字識別功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Python socket C/S結(jié)構(gòu)的聊天室應(yīng)用實現(xiàn)

    Python socket C/S結(jié)構(gòu)的聊天室應(yīng)用實現(xiàn)

    這篇文章主要介紹了Python socket C/S結(jié)構(gòu)的聊天室應(yīng)用實現(xiàn),需要的朋友可以參考下
    2014-11-11
  • 使用Python求解帶約束的最優(yōu)化問題詳解

    使用Python求解帶約束的最優(yōu)化問題詳解

    今天小編就為大家分享一篇使用Python求解帶約束的最優(yōu)化問題詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • OpenCV特征提取與檢測之Shi-Tomasi角點檢測器

    OpenCV特征提取與檢測之Shi-Tomasi角點檢測器

    在角點檢測的世界里哈瑞斯無疑是最重要的方法之一,但Shi-Tomasi作為改進(jìn)的算法也有很大應(yīng)用場景,尤其是動態(tài)跟蹤用的還比較多,這篇文章主要給大家介紹了關(guān)于OpenCV特征提取與檢測之Shi-Tomasi角點檢測器的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • Python實現(xiàn)3行代碼解簡單的一元一次方程

    Python實現(xiàn)3行代碼解簡單的一元一次方程

    這篇文章主要介紹了Python實現(xiàn)3行代碼解簡單的一元一次方程,很適合Python初學(xué)者學(xué)習(xí)借鑒,需要的朋友可以參考下
    2014-08-08

最新評論

江油市| 泰和县| 海林市| 南京市| 南昌市| 张家港市| 平遥县| 桐城市| 磴口县| 湖南省| 印江| 保定市| 杨浦区| 全州县| 临高县| 安化县| 石屏县| 繁峙县| 泽普县| 高雄县| 富民县| 威海市| 兴安盟| 张掖市| 玛曲县| 湛江市| 黎城县| 中牟县| 葫芦岛市| 静乐县| 新邵县| 新竹市| 闸北区| 博白县| 海原县| 芒康县| 富川| 洪泽县| 乌拉特中旗| 大冶市| 南充市|