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