<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
代理類主要功能是將一個類範例的屬性存取和控制代理到程式碼內部另外一個範例類,將想對外公佈的屬性的存取和控制權交給代理類來操作,保留不想對外公佈的屬性的存取或控制權,比如唯讀存取,紀錄檔功能
1.代理類實現被代理類的屬性存取和修改許可權控制
2.異常捕獲代理類的簡化範例
目標:實現類Product
的範例屬性讓另一個類Proxy
來代理存取和控制,想將對外公佈的屬性交給代理類讓外部存取和控制,不想對外公佈的屬性無法通過代理來存取和控制,這裡不想對外公佈的屬性約定用下劃線命名開頭
# proxy_example1.py # 以下是一個代理類實現唯讀存取的範例 # 目標:代理後只能存取和修改Product的公開屬性,私有屬性_current只能檢視不能修改 class Product: def __init__(self, price, quantity): self.price = price self.quantity = quantity self._current = 123 # 只暴露代理類Proxy給外部使用 class Proxy: def __init__(self, obj): self._obj = obj def __getattr__(self, item): # 本範例沒有找到的屬性會執行__getattr__方法 if item.startswith("_"): # 約定下劃線開頭的方法不能存取到被代理的類,只會存取到代理類 raise Exception(f"{item} not found") # Product存在的私有屬性也不希望被外部知道 return getattr(self._obj, item) def __setattr__(self, key, value): if key.startswith("_"): # 約定下劃線開頭的方法不能存取到被代理的類,只會存取到代理類 # 注:這裡不能raise,這會導致Proxy的範例都無法建立(__dict__等屬性無法建立) super(Proxy, self).__setattr__(key, value) # 避免無限迴圈 else: setattr(self._obj, key, value) # 要求只能刪除非下劃線開頭的屬性 def __delattr__(self, item): if item.startswith("_"): super(Proxy, self).__delattr__(item) # 避免無限迴圈 else: delattr(self._obj, item) def test_getattr(): p = Product(10, 1) pp = Proxy(p) print(pp.price) print(pp._curr) def test_setattr(): p = Product(10, 2) pp = Proxy(p) pp.abc = 1 print(pp.abc, p.abc) pp._curr = 10000 print(pp._curr) # 私有屬性,設定給了代理類 print(p._curr) # raise an error, 被代理的類Product的屬性沒有設定成功也無法存取 def test_delattr(): p = Product(10, 2) pp = Proxy(p) pp.abc = 123 print(pp.abc, p.abc) # 刪除公開屬性 del pp.abc # 成功 # print(pp.abc, p.abc) # 已被刪除 # # 刪除私有屬性 # del pp._curr # 會嘗試刪除Proxy的私有屬性,raise AttributeError: _curr # 先建立在刪除 pp._def = 123 # 這個操作只會設定Proxy的範例屬性 print(pp._def) # 存取的是Proxy範例屬性,被代理的Product範例沒有建立_def屬性 # del pp._def # 刪除的是Proxy的範例屬性 # print(pp._def)
測試獲取屬性
if __name__ == '__main__': test_getattr()
輸出:
10
...
Exception: _curr not found
...
測試設定屬性
if __name__ == '__main__': test_delattr()
輸出
1 1
10000
...
AttributeError: 'Product' object has no attribute '_curr'
...
測試刪除屬性
if __name__ == '__main__': test_delattr()
輸出
123 123
123
注:以雙下劃線開頭和結尾的方法無法被代理,想要使用,必須在代理類中定義出這個方法,然後重定向到被代理的類的方法,比如你想使用isinstance()
方法就要在Proxy
偽造定義__class__
屬性,想要使用len()
方法就要在Proxy
重定向返回到被代理的類的len方法
# proxy_example2.py class Product: def __init__(self, price, quantity): self.price = price self.quantity = quantity self._current = 123 def __len__(self): return 111 # 只暴露代理類Proxy給外部使用 class Proxy: def __init__(self, obj): self._obj = obj def __getattr__(self, item): # 本範例沒有找到的屬性會執行__getattr__方法 if item.startswith("_"): # 約定下劃線開頭的方法不能存取到被代理的類,只會存取到代理類 raise Exception(f"{item} not found") # Product存在的私有屬性也不希望被外部知道 return getattr(self._obj, item) def __setattr__(self, key, value): if key.startswith("_"): # 約定下劃線開頭的方法不能存取到被代理的類,只會存取到代理類 # 注:這裡不能raise,這會導致Proxy的範例都無法建立(__dict__等屬性無法建立) super(Proxy, self).__setattr__(key, value) # 避免無限迴圈 else: setattr(self._obj, key, value) # 要求只能刪除非下劃線開頭的屬性 def __delattr__(self, item): if item.startswith("_"): super(Proxy, self).__delattr__(item) # 避免無限迴圈 else: delattr(self._obj, item) @property def __class__(self): # 偽造類 return self._obj.__class__ def __len__(self): return len(self._obj) def test_instance(): p = Product(10, 2) pp = Proxy(p) print(pp.__class__) print(isinstance(pp, Product)) # 如果不偽造__class__,會返回False def test_len(): p = Product(10, 2) pp = Proxy(p) print(len(pp)) # 如果Proxy範例不定義__len__方法,會報錯TypeError: object of type 'Proxy' has no len()
測試偽造的範例class型別
if __name__ == '__main__': test_instance()
輸出
<class '__main__.Product'>
True
測試獲取長度
if __name__ == '__main__': test_len()
輸出
111
捕獲web server報錯紀錄檔並執行例外處理的範例
# logger_proxy.py # -*- coding:utf-8 -*- from functools import wraps class DAL: @classmethod def dm1(cls, req, *args): print("dm1...", f"{req=}") print(1/0) # 故意丟擲異常 return "dm1" class BLL: @classmethod def bm1(cls, req): print("bm1...", f"{req=}") return DAL.dm1(req) class Application: def __init__(self, req): self.req = req self._p = "private attr" def hd1(self): return BLL.bm1(self.req) class LoggerProxy: def __init__(self, obj): self._obj = obj def __getattr__(self, item): # LoggerProxy類範例沒獲取到的屬性會執行這個方法 attr = getattr(self._obj, item) if callable(attr): # 獲取到了方法,則處理異常捕獲 @wraps(attr) def wrapped_method(*args, **kwargs): # print(f"Before access to attribute/method: {item}") try: method = attr(*args, **kwargs) except ZeroDivisionError: # 捕獲異常然後處理... raise Exception(f"{attr.__name__} received a zero division error.") # print(f"After attribute/method {item} returned") return method return wrapped_method else: # 獲取到了屬性,直接返回 return attr if __name__ == '__main__': lp = LoggerProxy(Application("abc")) print(lp.req) print(lp._p) print(lp.hd1())
執行輸出
abc
private attr
bm1... req='abc'
dm1... req='abc'
Traceback...
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback...
Exception: hd1 received a zero division error.
本節主要的內容是實現了一個代理類,達到代理存取和控制某個類的屬性並避免將私有屬性暴露給外部,需要注意的是,一些特殊方法,也就是python雙下劃線開頭和結尾的方法,如果想要被代理類存取和控制,就必須在代理類中也定義對應的實際方法,另外,範例中主要是以下劃線開頭的方法作為私有屬性的約定,也可以使用其他約定,這樣在代理方法中的存取和修改時做出相應的判斷即可
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45