1. 程式人生 > >python超程式設計之實現定製類--使用描述符,__slots__,__new__篇

python超程式設計之實現定製類--使用描述符,__slots__,__new__篇

問題:實現一個類,要求行為如同namedtuple:只存在給定名稱的屬性,不允許動態新增例項屬性。

主要知識點在於: __slots__、描述符及property、__new__的使用

程式碼如下:

 1 """
 2 執行環境
 3 python 3.7+
 4 """
 5 from collections import namedtuple, OrderedDict
 6 
 7 #以下為要包裝的物件:1個命名元組,用於儲存計數,並對外傳遞資訊
 8 Counter = namedtuple("Counter", "total put OK failed recorded keys count
", 9 defaults=(0, 0, 0, 0, 0, 0, 0)) 10 11 class Demo: 12 """ 13 使用__slots__,__new__及描述符實現定製類 14 只能使用Counter中的屬性進行存取 15 """ 16 #引入__slots__特殊屬性用於控制例項屬性 17 #_dict用於儲存內部資料,此處未實現保護,可用定製描述符實現保護 18 __slots__ = list(Counter._fields)+['_dict'] 19 def __new__(cls):
20 """ 21 使用__new__特殊方法用於生成類例項之前配置類模板 22 因為描述符及特性(property)都是附在類上,而不是在例項上 23 """ 24 for f in Counter._fields: 25 #動態生成描述符或特性,用於控制屬性存取 26 #python內建的property就是特殊的描述符,可以用partialmethod包裝後在此處使用.此處未展示 27 #自己實現描述符當然更具定製性 28 setattr(cls,f,Descriptor(f))
29 return super().__new__(cls) 30 def __init__(self): 31 self._dict={} 32 for f in Counter._fields: 33 self._dict[f]=0 34 35 def update(self, n: Counter = None, **kargs): 36 """ 37 使用數值累加計數器 38 當Counter與鍵引數同時提供時,鍵值為準 39 """ 40 41 #描述符實現 42 class Descriptor: 43 def __init__(self,storage_name:str): 44 self.storage_name=storage_name 45 def __set__(self,instance,value): 46 print('from descriptor..') 47 instance._dict[self.storage_name]=value 48 def __get__(self,instance,owner): 49 return instance._dict[self.storage_name] 50 51 #也可以用以下特性工廠函式實現 52 def make_property(store_name:str)->property: 53 def getter(instance): 54 print('from property getter') 55 return instance._dict[store_name] 56 def setter(instance,value): 57 print('from property setter') 58 instance._dict[store_name]=value 59 return property(getter,setter)

補充說明,以上部分邏輯並未完整考慮和優化,只是對類定製及屬性存取做實現演示。另外的實現方法可參考上篇:

python超程式設計之使用動態屬性實現定製類--特殊方法__setattr__,__getattribute__篇 https://www.cnblogs.com/zward/p/10041162.html