Python Cookbook-6.5 繼承的替代方案——自動托管

任務

你需要從某個類或者類型繼承,但是需要對繼承做一些調整。比如,需要選擇性地隱藏某些基類的方法,而繼承并不能做到這一點。

解決方案

繼承是很方便的,但它并不是萬用良藥。比如,它無法讓你隱藏基類的方法或者屬性。而自動托管技術則提供了一種很好的選擇。假設需要把一些對象封起來變成只讀對象從而避免意外修改的情況。那么,除了禁止屬性設置的功能,還需要隱藏修改屬性的方法。下面我們給出一個辦法:

#同時支持2.3和2.4
try:set
except NameError:from sets import Set as set
class ROError(AttributeError):pass
class Readonly:#這里并沒有用繼承,我們會在后面討論其原因mutators = {list:set('''__delitem__ __delslice__ __iadd__ __imul____setitem__ __setslice__ __append extend insert pop remove sort'''.split()),dict:set('''__delitem__ __setitem__ clear pop popitemsetdefault update'''.split()),}def __init__(self,o):object.__setattr__(self,'_o',o)object.__setattr__(self,'_no',self.mutators.get(type(o),()))def __setattr__(self,n,y):raise ROError,"Can't set attr %r on RO obiect" %n def __delattr__(self,n):raise ROError,"Can't del attr %r from Ro object" %n def __getattr__(self,n):if n in self._no:raise ROError,"Can't get attr %r from Ro object" %nreturn getattr(self._o, n)

通過修改 mutators,即 Readonly.mutators[sometype] = the_mutators,還可以輕松地增加其他需要處理的類型。

討論

自動托管是一種強大而通用的技術。在本節的例子中,通過使用這個技術我們能得到和類繼承幾乎完全一樣的效果,同時還能隱藏一些名字。我們在任務中使用這個模擬的子類將一些對象封裝起來,使之變成只讀對象。它的性能也許不如真正的繼承,但另一方面,作為補償,我們獲得了更好的靈活度和更精細的粒度控制。

基本的想法是,我們的類的每個實例都含有我們想要封裝的類型的實例。每當客戶代碼試圖從我們的類的實例中獲取屬性時,除非該屬性已經在類中被定義了(比如定義在 Readonly類的 mutators 字典中),否則__getattr__ 在完成檢查之后,會透明地將這個請求轉交給被封裝的實例。在Python中,方法同樣也是屬性,訪問的方式也一樣,所以無論是訪問方法還是屬性,代碼無須改變。用來訪問屬性的__getattr__方法同時也可用于訪問方法。

解決方案的注釋沒有解釋不使用繼承的原因,這里我們會給出一點解釋。這種基于__getattr__的方式也可用于特殊方法,但僅對舊風格類的實例有效。在新的對象模型中,Python 操作直接通過類的特殊方法來進行,而不是實例的。關于這個問題的更多內容可以在 6.6 節和 20.8節中看到。本節采用的方案——讓 Readonly 類成為舊風格類,從而避開這個問題,并把相關內容留到其他章節——在真實的生產代碼中是不值得推薦的。我在這里用僅僅是為了控制篇幅,同時避免重復其他章節的內容。

setattr__的角色類似于__getattr,當客戶代碼設置實例的屬性時,它就會被調用,這個任務要求某些屬性為只讀,我們只需簡單地禁止屬性訪問操作即可。記住,要在方法的代碼編寫中避免激發對__setattr__的調用,在有__setattr__的類的方法中你不應該使用self.n = v這樣的語句。最簡單的是直接把設置操作委托給類object,如同類Readonly在它的__init__ 方法中所做的那樣。方法__delattr__完成了最后拼圖,它會處理那些試圖從實例中刪除屬性的操作。

以自動托管方式完成的封裝并不適用于采用了類型檢查的客戶代碼或者框架代碼。在那種情況下,客戶代碼或框架代碼完全破壞了多態性,代碼本身應該是被重寫的。記住不要在你自己的代碼中使用類型檢查,因為你可能根本無須那么做。見6.13節提供的更好的選擇。

在 Python 的老版本中,自動托管的流行程度甚至比現在還高,那是因為當時 Python 不支持從內建的類型繼承。而對于現在的 Python,從內建類型繼承是允許的,因此自動托管就用得不那么頻繁了。不過,自動托管仍然具有它的地位——它只是稍微遠離了聚光燈一點點。托管比繼承更加靈活,而有時這種靈活是無價的。除了選擇性地托管(從而高效地實現了某些屬性的“隱藏”),一個對象還可以在不同的時間托管給不同的子對象,或者一次托管給多個子對象,繼承無法提供任何能夠與之相比的特性。下面給出托管給多個特定子對象的例子。假設你有個類,提供各種“轉發方法”,比如:

class Pricing(object):def __init__(self,location,event):self.location = locationself.event = eventdef setlocation(self,location):self.location = locationdef getprice(self):return self.location.getprice()def getquantity(self):return self.location.getquantity()def getdiscount(self):return self.event.getdiscount()and many more such methods

繼承很明顯不適用,因為 Pricing的實例需要托管給特定的location和event實例,這些實例在初始化階段傳入而且可能會被修改。自動托管的補救方法是:

class AutoDelegator(object):delegates = ()do_not_delegate = ()def __getattr__(self,key):if key not in self.do_not_delegate:for d in self.delegates:try:return getattr(d,key)except AttributeError:passraise AttributeError,key
class Pricing(AutoDelegator):def __init__(self,location,event):self.delegates = [location,event]def setlocation(self,location):self.delegates[0] = location

在此例中,我們沒有托管屬性的刪除和設置,而只是托管了屬性的獲取(還有一些非特殊方法)。當然,這個方式只有在我們想要托管的各個對象的方法(以及其他屬性)不會互相干擾的情況下才會充分有效,比如,location最好不要有個getdiscount方法否則它會搶先進行方法的托管,而此方法原本應該是由event對象來執行的。

如果一個需要大量托管的類涉及這種問題,它可以簡單地定義一些對應的方法,這是因為只有在用別的方式無法找到屬性和方法時,__getattr__才會介入。而通過do_not_delegate 屬性還可以隱藏托管對象的一些屬性和方法,而且它也可以被子類改寫。舉個例子,如果類 Pricing 想要隱藏一個叫做 setdiscount 的方法,此方法由 event提供,做一點點修改就可以了:

class Pricing(AutoDelegator):
do_not_delegate = ('set_discount')

其余部分則與前面代碼片段相同。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/77207.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/77207.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/77207.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

長短期記憶網絡:從理論到創新應用的深度剖析

一、引言 1.1 研究背景 深度學習在人工智能領域的發展可謂突飛猛進,而長短期記憶網絡(LSTM)在其中占據著至關重要的地位。隨著數據量的不斷增長和對時序數據處理需求的增加,傳統的神經網絡在處理長序列數據時面臨著梯度消失和梯…

vue3.2 + element-plus 實現跟隨input輸入框的彈框,彈框里可以分組或tab形式顯示選項

效果 基礎用法&#xff08;分組選項&#xff09; 高級用法&#xff08;帶Tab欄&#xff09; <!-- 彈窗跟隨通用組件 SmartSelector.vue --> <!-- 彈窗跟隨通用組件 --> <template><div class"smart-selector-container"><el-popove…

C語言中冒泡排序和快速排序的區別

冒泡排序和快速排序都是常見的排序算法&#xff0c;但它們在原理、效率和應用場景等方面存在顯著區別。以下是兩者的詳細對比&#xff1a; 一、算法原理 1. 冒泡排序 原理&#xff1a;通過重復遍歷數組&#xff0c;比較相鄰元素的大小&#xff0c;并在必要時交換它們的位置。…

軟件信息安全性測試如何進行?有哪些注意事項?

隨著信息技術的高速發展&#xff0c;軟件已經成為我們生活和工作中不可或缺的一部分。然而&#xff0c;隨著軟件產品的廣泛普及&#xff0c;軟件信息安全性問題也日益凸顯&#xff0c;因此軟件信息安全性測試必不可少。那么軟件信息安全性測試應如何進行呢?在進行過程中又有哪…

springboot集成mybaits-generator自動生成代碼

文章目錄 概述創建springboot項目pom文件aplication.yml代碼生成類mybatis-plus提供的變量controller模板mapper模板總結 概述 創建springboot項目&#xff0c;在這里使用的是springboot 2.6.13版本&#xff0c;引入的項目依賴包如pom文件所寫&#xff0c;jdk使用1.8&#xff…

數據庫脫褲

假設你已經getshell 找到mysql賬號密碼。 網站要連接mysql&#xff0c;就需要把mysql的賬號密碼保存在一個php文件中&#xff0c;類似config.php、common.inc.php等&#xff0c;在shell中&#xff0c;讀取這些文件&#xff0c;找到其中信息即可 下面是一些常見平臺的配置文…

leetcode 337. House Robber III

用動態規劃的思想解決這道題。 對于每一個節點&#xff0c;只有兩種可能&#xff0c;偷或者不偷。 對于一顆以root為根節點的二叉樹&#xff0c;定義rob表示偷root節點能從這棵二叉樹偷到的最大金額。定義notrob表示不偷root節點能從這棵二叉樹偷到的最大金額。 遞推公式分析…

ES和MySQL概念對比

基本概念 ES和MySQL都屬于數據庫&#xff0c;不過各有各的特性&#xff0c;大致使用方法與MySQL類似并無區別。 MySQL&#xff1a;擅長事務持有ACID的特性&#xff0c;確保數據的一致性和安全。 ES&#xff1a;持有倒排索引&#xff0c;適合海量數據搜索和分析。 ES和MySQL如何…

【python】針對Selenium中彈框信息無法定位的問題,以下是綜合解決方案及注意事項:

一、常見原因分析 1.1 彈窗類型不匹配 若彈窗為alert&#xff0c;需使用driver.switch_to.alert處理&#xff1b; 若為confirm或prompt&#xff0c;同樣適用該方法。 1.2 窗口句柄切換問題 新窗口或彈窗可能開啟新句柄&#xff0c;需先通過driver.window_handles切換到對應句…

歐拉服務器操作系統安裝MySQL

1. 安裝MySQL服務器?? 1. 更新倉庫緩存 sudo dnf makecache2. 安裝MySQL sudo dnf install mysql-server2. 初始化數據庫? sudo mysqld --initialize --usermysql3. 啟動數據庫服務 # 啟動服務 sudo systemctl start mysqld# 設置開機自啟 sudo systemctl enable mysql…

SQLark:一款國產免費數據庫開發和管理工具

SQLark&#xff08;百靈連接&#xff09;是一款面向信創應用開發者的數據庫開發和管理工具&#xff0c;用于快速查詢、創建和管理不同類型的數據庫系統&#xff0c;目前可以支持達夢數據庫、Oracle 以及 MySQL。 對象管理 SQLark 支持豐富的數據庫對象管理功能&#xff0c;包括…

Spring Boot 中的自動配置原理

2025/4/6 向全棧工程師邁進&#xff01; 一、自動配置 所謂的自動配置原理就是遵循約定大約配置的原則&#xff0c;在boot工程程序啟動后&#xff0c;起步依賴中的一些bean對象會自動的注入到IOC容器中。 在講解Spring Boot 中bean對象的管理的時候&#xff0c;我們注入bean對…

Mysql8配置文件

Mysql8配置文件 修改my.cnf----配置持久化鍵(persistence key)配置表名不區分大小寫 修改my.cnf----配置持久化鍵(persistence key) MySQL8初始化數據庫之前配置好這些變量值&#xff0c;初始化數據庫之后可能無法修改這個值。 # 服務端配置 [mysqld] ######## 數據目錄和基…

關于系統架構思考,如何設計實現系統的高可用?

緒論、系統高可用的必要性 系統高可用為了保持業務連續性保障&#xff0c;以及停機成本量化&#xff0c;比如在以前的雙十一當天如果出現宕機&#xff0c;那將會損失多少錢&#xff1f;比如最近幾年Amazon 2021年30分鐘宕機損失$5.6M。當然也有成功的案例&#xff0c;比如異地…

【Unity筆記】實現可視化配置的Unity按鍵輸入管理器(按下/長按/松開事件 + UnityEvent綁定)

【Unity筆記】實現可視化配置的Unity按鍵輸入管理器 適用于角色控制、技能觸發的Unity按鍵輸入系統&#xff0c;支持UnityEvent事件綁定、長按/松開監聽與啟用開關 一、引言 在 Unity 游戲開發中&#xff0c;處理鍵盤輸入是最常見的交互方式之一。尤其是角色控制、技能釋放、菜…

Fortran 中使用 C_LOC 和 C_F_POINTER 結合的方法來實現不同類型指針指向同一塊內存區域

在 Fortran 中&#xff0c;可以使用 C_LOC 和 C_F_POINTER 結合的方法來實現不同類型指針指向同一塊內存區域。以下是具體方法和示例&#xff1a; 關鍵步驟&#xff1a; 獲取內存地址&#xff1a;用 C_LOC 獲取原始數組的 C 地址。類型轉換&#xff1a;用 C_F_POINTER 將地址轉…

Spring Boot整合Kafka的詳細步驟

1. 安裝Kafka 下載Kafka&#xff1a;從Kafka官網下載最新版本的Kafka。 解壓并啟動&#xff1a; 解壓Kafka文件后&#xff0c;進入bin目錄。 啟動ZooKeeper&#xff1a;./zookeeper-server-start.sh ../config/zookeeper.properties。 啟動Kafka&#xff1a;./kafka-server-…

【含文檔+PPT+源碼】基于微信小程序的學校體育館操場預約系統的設計與實現

課程簡介&#xff1a; 本課程演示的是一款基于微信小程序的學校體育館操場預約系統的設計與實現&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習者。 1.包含&#xff1a;項目源碼、項目文檔、數據庫腳本、軟件工具等所有資料 2.帶你從…

【Leetcode-Hot100】最大子數組和

題目 解答 class Solution(object):def maxSubArray(self, nums):""":type nums: List[int]:rtype: int"""len_nums len(nums)result -1e5left_fit, right_fit 0, len_nums-1if len_nums 1:return nums[0]sum_left, sum_right 0, 0while r…

txt、Csv、Excel、JSON、SQL文件讀取(Python)

txt、Csv、Excel、JSON、SQL文件讀取&#xff08;Python&#xff09; txt文件讀寫 創建一個txt文件 fopen(rtext.txt,r,encodingutf-8) sf.read() f.close() print(s)open( )是打開文件的方法 text.txt’文件名 在同一個文件夾下所以可以省略路徑 如果不在同一個文件夾下 ‘…