一、UserDict概述
UserDict 模組中的 UserDict 類是在python中經常使用的類,儲存在Python 安裝目錄的 lib 目錄下UserDict.py。其高仿字典(Dictionary)開啟之後可見如下:
1 ""A more or less complete user-defined wrapper around dictionary objects.""" 2 3 class UserDict: [1] 4 def __init__(self, dict=None, **kwargs): [2] 5 self.data = {} [3] 6 if dict is not None: [4] 7 self.update(dict) [5] 8 if len(kwargs): 9 self.update(kwargs)10 def __repr__(self): return repr(self.data)11 def __cmp__(self, dict):12 if isinstance(dict, UserDict):13 return cmp(self.data, dict.data)14 else:15 return cmp(self.data, dict)16 def __len__(self): return len(self.data)
..................省略
注意:
[1]. UserDict 是一個基類,不是從任何其他類繼承而來
[2].通過在 dict 參數中傳入一個字典來定義初始值
[3].Python 支援資料屬性,如上的 data (在C#、C++叫資料成員,java中叫執行個體變數)。它是由某個特定的類執行個體所擁有的資料,在本例中,每個 UserDict 執行個體將擁有一個 data 資料屬性。
引用:(1).要從類外的代碼引用這個屬性,需要用執行個體的名字限定它,instance.data,限定的方法與你用模組的名字來限定函數一樣
(2).要在類的內部引用一個資料屬性,我們使用 self 作為限定符
習慣上,所有的資料屬性都在 __init__ 方法中初始化為有意義的值。然而,這並不是必須的,因為資料屬性,象局部變數一樣,當你首次賦給它值的時候突然產生。
[4].if ....is...文法
[5].update 方法是一個字典複製器:它把一個字典中的鍵和值全部拷貝到另一個字典。 這個操作 並不 事先清空目標字典,如果一些鍵在目標字典中已經存在,則它們將被覆蓋,那些鍵名在目標字典中不存在的則不改變。應該把 update 看作是合并函數,而不是複製函數。
二、UserDict 常規方法
1 def clear(self): #[1] 2 self.data.clear() #[2] 3 def copy(self): #[3] 4 if self.__class__ is UserDict: #[4] 5 return UserDict(self.data) 6 import copy 7 return copy.copy(self) #[5] 8 def keys(self): 9 self.data.keys()10 def items(self):11 self.data.items()12 def values(self):13 self.data.values()
注意:封裝類的基本技術:
將一個真正的字典 (data) 作為資料屬性儲存起來,定義所有真正字典所擁有的方法,並且將每個類方法重新導向到真正字典上的相應方法。(如上的clear,對應dictionary中的clear()方法)
1 從 dictionary 中刪除元素 2 >>> d 3 {'server': 'mpilgrim', 'uid': 'sa', 'database': 'master',42: 'douglas', 'retrycount': 3} 4 >>> del d[42] 5 >>> d 6 {'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3} 7 >>> d.clear() 8 >>> d 9 10 del 允許您使用 key 從一個 dictionary 中刪除獨立的元素。 11 clear 從一個 dictionary 中清除所有元素。注意空的大括弧集合表示一個沒有元素的 dictionary。
[1].clear 是一個普通的類方法,可以在任何時候被任何人公開調用。注意,clear 象所有的類方法一樣(常規的或專用的),使用 self 作為它的第一個參數。(記住,當你調用方法時,不用包括 self;這件事是 Python 替你做的。)
[2].真正字典的 copy 方法會返回一個新的字典,它是原始字典的原樣的複製(所有的鍵-值對都相同)。但是 UserDict 不能簡單地重新導向到 self.data.copy,因為那個方法返回一個真正的字典,而我們想要的是返回同一個類的一個新的執行個體,就象是 self。
[3].我們使用 __class__ 屬性來查看是否 self 是一個 UserDict,如果是,太好了,因為我們知道如何拷貝一個 UserDict:只要建立一個新的 UserDict ,並傳給它真正的字典,這個字典已經存放在 self.data 中了。 然後你立即返回這個新的 UserDict,你甚至於不需要再下面一行中使用 import copy。
[4].如果 self.__class__ 不是 UserDict,那麼 self 一定是 UserDict 的某個子類(如可能為 FileInfo),生活總是存在意外。 UserDict 不知道如何產生它的子類的一個原樣的拷貝,例如,有可能在子類中定義了其它的資料屬性,所以我們只能完全複製它們,確定拷貝了它們的全部內容。幸運的是,Python 帶了一個模組可以正確地完成這件事,它叫做 copy。能夠拷貝任何 Python 對象.
[5].其餘的方法是直截了當的重新導向到 self.data 的內建函數上。
三、 直接繼承自內建資料類型 dict
注意:dict是內建的資料類型,如同內建函數一般,可以在任何地方使用。在python中,可以直接繼承自內建資料類型dict,如下:
1.繼承自UserDict.UserDict
1 #繼承自 UserDict.UserDict 2 #import UserDict 這個錯誤,一定要匯入UserDict模組的UserDict類3 from UserDict import UserDict4 class FileInfo(UserDict):5 "store file metadata"6 def __init__(self, filename=None):7 UserDict.__init__(self) 8 self["name"] = filename
2.直接繼承自內建資料類型 dict
1 #直接繼承自內建資料類型 dict2 class demo(dict):3 def __init__(self,test=None):4 self["name"]=test
我們發現第二種精簡了許多。它們之間的區別如下3點:
(1)不需要匯入 UserDict 模組,因為 dict 是已經可以使用的內建資料類型
(2)繼承方式不同,一個是繼承自 UserDict.UserDict ,另一個直接繼承自 dict
(3)UserDict 內部的工作方式要求你手工地調用它的 __init__ 方法去正確初始化它的內部資料結構。 dict 並不這樣工作,它不是一個封裝所以不需要明確的初始化。
四、python類的深入[1]
1.關於重載
在各程式設計語言中大致分為兩種重載方式:
(1).通過參數列表的重載,一個類可以有同名的多個方法,但這些方法它們參數個數不同,或參數的類型不同,如java
(2).支援通過參數名的重載,一個類可以有同名的多個方法,這些方法有相同類型,相同個數的參數,但參數名不同如(PL/SQL)
不過注意:Python 兩種都不支援!
總之是沒有任何形式的函數重載。一個 __init__ 方法就是一個 __init__ 方法,不管它有什麼樣的參數。每個類只能有一個 __init__ 方法,並且如果一個子類擁有一個 __init__ 方法,它總是覆蓋父類的 __init__ 方法,甚至子類可以用不同的參數列表來定義它。子類可以覆蓋父類中的方法。
2.關於資料屬性
應該總是在 __init__ 方法中給一個執行個體的所有資料屬性賦予一個初始值。這樣做將會節省你在後面調試的時間,不必為捕捉因使用未初始化(也就是不存在)的屬性而導致的 AttributeError 異常費時費力。
在 Java 中,靜態變數(在 Python 中叫類屬性)和執行個體變數(在 Python 中叫資料屬性)兩者是緊跟在類定義之後定義的(一個有 static 關鍵字,一個沒有)。在 Python 中,只有類屬性可以定義在這裡,資料屬性定義在 __init__ 方法中。
參考 Dive Into Python