1. 程式人生 > >python類特性

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>')

即完成泛型功能。

演示程式碼下載連結