1. 程式人生 > >python語言基礎九

python語言基礎九

十九、 描述符

    描述符就是將某種特殊型別的類的例項指派給另一個類的屬性。

    所謂特殊型別, 要求至少實現以下三個方法中的一個(全部實現也可以)

__get__(self, instance, owner)    定義當描述符的值被取得時的行為     用於訪問屬性, 他返回屬性的值 __set__(self, instance, value)    定義當描述符的值被改變時的行為     將在屬性分配操作中呼叫, 不返回任何值 __delete__(self, instance)    定義當描述符的值被刪除時的行為     控制刪除操作,不返回任何內容

class MyProperty:     def __init__(self, f_get=None, f_set=None, f_del=None):         self.f_get = f_get         self.f_set = f_set         self.f_del = f_del

    def __get__(self, instance, owner):         return self.f_get(instance)

    def __set__(self, instance, value):         return self.f_set(instance,value)

    def __delete__(self, instance):         self.f_del(instance)

class C:     def __init__(self):         self._x = None

    def get_x(self):         return self._x

    def set_x(self, value):         self._x = value

    def del_x(self):         del self._x

    x = MyProperty(get_x, set_x, del_x)

c = C() c.x = "xiaoming" print(c.x)                    xiaoming

del c.x print(c.x)                    AttributeError: 'C' object has no attribute '_x'

二十、 定製序列

    協議是什麼?     協議與其他程式語言中的介面很相似, 它規定你哪些方法必須要定義。 然而, 在python中的協議就顯得不那麼正式,      事實上, 在python中, 協議更像是一種指南。

    鴨子型別 : 當看到一隻鳥走起來像鴨子, 遊起來像鴨子, 叫起來也像鴨子, 那麼這隻鳥就可以被稱為鴨子。

    如果你希望定製的容器是不可變的話, 你只需要定義 __len__() 和 __getitem__() 方法。

    如果你希望定製的容器是可變的話, 除了 __len__() 和 __getitem__() 方法,      你還需要定義 __setitem__() 和 __delitem__() 兩個方法。

        __len__() 方法 :                  定義當被 len() 呼叫時的行為(返回容器中元素的個數)

        __getitem__() 方法:                 定義獲取容器中指定元素的行為, 相當於 self[key]

        __setitem__() 方法:                 定義設定容器中指定元素的行為,  相當於 self[key] = value

        __delitem__() 方法:                 定義刪除容器中指定元素的行為。 相當於 del self[key]

不可變容器 : 

class CountList:

    def __init__(self, *args):         self.values = [x for x in args]         self.count = {}.fromkeys(range(len(self.values)), 0)

    def __len__(self):         print('你正在呼叫 __len__ 方法啊')         return len(self.values)

    def __getitem__(self, item):         print('你正在呼叫 __getitem__ 方法啊')         self.count[item] += 1         return self.values[item]

count_list1 = CountList(1, 3, 5, 7, 9)

count_list2 = CountList(2, 4, 6, 8, 10) print(count_list1[1]) 你正在呼叫 __getitem__ 方法啊 3

print(count_list2[1]) 你正在呼叫 __getitem__ 方法啊 4

print(count_list1[1] + count_list2[1]) 你正在呼叫 __getitem__ 方法啊 你正在呼叫 __getitem__ 方法啊 7

print(count_list1.count) {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}

print(count_list2.count) {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}

count_list1[1] = 5 print(count_list1[1])                TypeError: 'CountList' object does not support item assignment

可變容器 : 

class CountList:

    def __init__(self, *args):         self.values = [x for x in args]         self.count = {}.fromkeys(range(len(self.values)), 0)

    def __len__(self):         print('你正在呼叫 __len__ 方法啊')         return len(self.values)

    def __getitem__(self, item):         print('你正在呼叫 __getitem__ 方法啊')         self.count[item] += 1         return self.values[item]

    def __setitem__(self, key, value):         print('正在呼叫 __setitem__ 方法啊')         self.values[key] = value

    def __delitem__(self, key):         print('正在呼叫 __delitem__ 方法啊')         del self.values[key]

count_list1 = CountList(1, 3, 5, 7, 9)

count_list1[1] = 5 正在呼叫 __setitem__ 方法啊

print(count_list1[1]) 你正在呼叫 __getitem__ 方法啊 5

del count_list1[1] 正在呼叫 __delitem__ 方法啊

二十一、迭代器          迭代器的特點 :      迭代,顧名思義就是重複做一些事很多次(就現在迴圈中做的那樣)。迭代器是實現了__next__()方法的物件(這個方法在呼叫時不需要任何引數),     它是訪問可迭代序列的一種方式,通常其從序列的第一個元素開始訪問,直到所有的元素都被訪問才結束。      [注意]:迭代器只能前進不能後退.     如果迭代到最後超出範圍, 則丟擲 :     StopIteration 

        迭代器需要可以被 iter() 和 next() 這兩個方法呼叫    。 【 實現兩個 __iter__()  和 __next__() 這兩個魔法方法 】

    建立迭代器 :          a、 使用內建的工廠函式iter(iterable)可以將可迭代序列轉換為迭代器

a = [1, 2, 3, 4]

print(type(a))                        <class 'list'>

print(next(a))                        TypeError: 'list' object is not an iterator

print(type(iter(a)))                <class 'list_iterator'>

print(next(iter(a)))                1

        b、 自定義迭代器。             由於Python中沒有“迭代器”這個類,因此具有以下兩個特性的類都可以稱為“迭代器”類:               1、有__next__()方法,返回容器的下一個元素或丟擲StopIteration異常                2、有__iter__()方法,返回迭代器本身

class Fibs:

    def __init__(self, n):         self.a = 0         self.b = 1         self.n = n

    def __iter__(self):         return self

    def __next__(self):         self.a, self.b = self.b, self.a + self.b         if self.a > self.n:             raise StopIteration         return self.a

for each in Fibs(30):     print(each)

輸出 :  1    1    2    3    5    8    13    21

二十二、 生成器     所謂的協調程式就是可以執行的獨立的函式呼叫, 函式可以暫停或者掛起, 並在需要的時候從程式離開的地方繼續或者重新開始。

    對於普通的函式, 一般都是從函式的第一行開始執行, 知道所有的行都執行完畢或者遇到 return 函式才結束。     一旦函式將控制權交還給呼叫者, 函式裡面的一切都結束了。 

    而 【生成器】 是一個特殊的【函式】, 呼叫可以在中斷、停止。 暫停之後, 他把控制權臨時交出來,      然後下次呼叫再接著上次離開的地方繼續執行。

    生成器關鍵字 : 【  yield  】

def my_gen():     print('生成器執行了。。。')     yield 1                            【 第一次呼叫在這裡結束】     yield 2                            【 第二次呼叫從這裡開始】

mg = my_gen() print('-'*50) print(next(mg)) print('-'*50) print(next(mg))

輸出 : 

-------------------------------------------------- 生成器執行了。。。 1 -------------------------------------------------- 2

生成器實現 斐波那契 : 

def fibs():     a = 0     b = 1     while True:         a, b = b, a + b         yield a

for each in fibs():     if each > 30:         break     print(each)

輸出 :  1    1    2    3    5    8    13    21