python類特性
習慣了C++和Java OO(面向物件)思想的程式設計師剛轉到python會有些不習慣,python中對很多操作都做了簡化,完全的面向過程程式設計也很容易(事實上很多人確實在這樣做),但是實際上python針對類提供了很多有用的特性,瞭解這些可以編寫更好的Python OO程式。
1.命名元組
預設的python元組訪問時,需要按照序號訪問,這樣一是不易閱讀二是擴充套件比較困難,python collections組提供了命名元組的功能解決此功能,元組直接當做物件,元素當做物件屬性即可。
import collections # 命名元組 def name_tuple_test(): User = collections.namedtuple('User', ['id', 'name', 'age', 'weight']) u = User(12, 'jim wen', 20, 140) print(u) print(u.id, u.name, u.age, u.weight)
2.函式物件
程式設計中我們經常抽象一個公用模型,通過指定回撥函式來完成功能的定製和補充,c++中可以指定函式指標來完成,但是函式指標的可擴充套件性和複用性有限,最常見的是需要針對不同情況給回撥一個初始值,這種情況更常用的做法是指定函式物件(過載()操作符);而在java中我們通常是指定一個介面來完成回撥。引入lamda表示式後,c++和java都可以藉助lamda表示式減少回撥程式設計工作。
而在python中我們因為所有的類或函式都是一級物件,所以常常習慣是直接指定函式。在一些擴充套件性要求更強的情況,需要我們使用函式物件,如下:
class FillDefaultValue(): def __init__(self, prefix): self.__data = prefix def __call__(self): return "other value-%d" %self.__data def function_object_test(): m = {"1": "one", "2": "two", "3": "three", "4": "four"} m_wrap = collections.defaultdict(FillDefaultValue(0), m) for i in xrange(1, 6): print("Index:%d , Result:%s\n" % (i, m_wrap[str(i)]))
這裡通過過載__call__實現函式物件,這裡藉助函式物件我們可以在生成函式物件時指定預設值。
3.操作符重寫
OO程式設計中,重寫操作符也是常用操作,特別在實現自定義資料結構時,為了和python內建操作保持同樣正規化,需要實現預設操作符重寫。和java類似,python提供了指定操作類的基類介面,我們繼承實現即可,這些介面在collections包中,如下我們實現一個最簡單的List類,繼承sequence基類:
class MyList(collections.Sequence): def __init__(self): self.__data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] def __getitem__(self, i): return self.__data.__getitem__(i) def __len__(self): return len(self.__data) def my_list_test(): l = MyList() for i in xrange(0, len(l)): print(l[i])
4.類泛型
簡單點說:類製造物件,傳入引數是資料;泛型製造類,傳入引數是類。python中型別操作得到簡化,通常我們只用到類->物件,但是有時會還是需要用到泛型。比如,需要定義一個函式來解析不同型別的Data,函式傳入不同的類,需要製造出不同的類物件並用製造的物件解析資料。python中沒有提供直接的泛型支援,但是通過classmethod屬性可以完成類似操作,類成員函式第一個引數是self,即在類物件上操作,classmethod類函式第一個引數是類名,函式體中直接生產對應類物件,某種程度上簡化了泛型的定義。
class GenericData():
def output(self):
pass
@classmethod
def create_class(cls, data):
return cls(data)
class JsonData(GenericData):
def __init__(self, data):
self.__data = json.loads(data, "utf-8")
def output(self):
print(self.__data['key'])
class XmlData(GenericData):
def __init__(self, data):
self.__data = ET.fromstring(data)
def output(self):
print(self.__data.tag, self.__data.text)
def dump_data_test(d, data):
d = d.create_class(data)
d.output()
如下呼叫:
dump_data_test(JsonData, '{"key":"Json Data"}')
dump_data_test(XmlData, '<key>Xml Data</key>')
即完成泛型功能。
演示程式碼下載連結