1. 程式人生 > >python元編程之實現定制類--使用描述符,__slots__,__new__篇

python元編程之實現定制類--使用描述符,__slots__,__new__篇

命名 pro failed htm rom 邏輯 lec 計數 for

問題:實現一個類,要求行為如同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

python元編程之實現定制類--使用描述符,__slots__,__new__篇