python之序列去重以及生成器、生成器函數、生成器表達式與迭代器淺談

首先要明確序列值類型是否可哈希,由於可哈希的值很簡單就能夠用 in /not in 寫個生成器去判斷,若是是不可哈希的就要去轉換爲可哈希的再用 in/not in 去判斷

原地不可變類型(可哈希):

  • 數字類型:int, float, decimal.Decimal, fractions.Fraction, complex
  • 字符串類型:str, bytes
  • tuple
  • frozenset
  • 布爾類型:True, False
  • None

原地可變類型(不可哈希):

  • list
  • dict
  • set
舉例可哈希序列去重
b=[1,2,3,1,2,5] def debque1(items): result=set() for item in items: if item not in result: yield item result.add(item) print(list(debque1(b))) #[1, 2, 3, 5]
舉例不可哈希序列去重
a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}] def debque2(items,key=None): result=set() for item in items: val=item if key is None else key(item) if val not in result: yield item result.add(val) print(list(debque2(a,key=lambda item:(item["x"],item["y"]))))   # [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]

這方法利用了生成器,科普一下生成器html

若是列表元素能夠按照某種算法推算出來,那咱們就能夠在循環的過程當中不斷推算出後續的元素,這樣就沒必要建立完整的list,從而節省大量的空間,因此zai在Python中,就出現了這種一邊循環一邊計算的機制,稱爲生成器:generator算法

生成器是迭代器的一種,使用yield返回值函數,每次調用yield會暫停,而可使用next()函數和send()函數恢復生成器。函數

要建立一個generator,有不少種方法,第一種方法很簡單,只有把一個列表生成式的[]中括號改成()小括號,就建立一個generatorspa

# 列表生成式
lis = [x*x for x in range(10)] print(lis) # 生成器
generator_ex = (x*x for x in range(10)) print(generator_ex) # 結果: # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # <generator object <genexpr> at 0x000002A4CBF9EBA0>

若是要一個個打印出來,能夠經過next()函數得到generator的下一個返回值:code

可是通常不這麼作,正確的方法是使用for循環,由於generator也是可迭代對象htm

 

  生成器函數:也是用def定義的,利用關鍵字yield一次性返回一個結果,阻塞,從新開始對象

   生成器表達式:返回一個對象,這個對象只有在須要的時候才產生結果blog

——生成器函數

爲何叫生成器函數?由於它隨着時間的推移生成了一個數值隊列。通常的函數在執行完畢以後會返回一個值而後退出,可是生成器函數會自動掛起,而後從新拾起急需執行,他會利用yield關鍵字關起函數,給調用者返回一個值,同時保留了當前的足夠多的狀態,可使函數繼續執行,生成器和迭代協議是密切相關的,可迭代的對象都有一個__next__()__成員方法,這個方法要麼返回迭代的下一項,要買引發異常結束迭代。隊列

# 函數有了yield以後,函數名+()就變成了生成器 # return在生成器中表明生成器的停止,直接報錯 # next的做用是喚醒並繼續執行 # send的做用是喚醒並繼續執行,發送一個信息到生成器內部
'''生成器'''
 
def create_counter(n): print("create_counter") while True: yield n print("increment n") n +=1 gen = create_counter(2) print(gen) print(next(gen)) print(next(gen)) 結果: <generator object create_counter at 0x0000023A1694A938> create_counter 2 increment n 3 Process finished with exit code 0

 yield是一個相似return 的關鍵字,迭代一次遇到yield的時候就返回yield後面或者右面的值。並且下一次迭代的時候,從上一次迭代遇到的yield後面的代碼開始執行ci

——生成器表達式

生成器表達式來源於迭代和列表解析的組合,生成器和列表解析相似,可是它使用尖括號而不是方括號

>>> # 列表解析生成列表
>>> [ x ** 3 for x in range(5)] [0, 1, 8, 27, 64] >>>
>>> # 生成器表達式
>>> (x ** 3 for x in range(5)) <generator object <genexpr> at 0x000000000315F678>
>>> # 二者之間轉換
>>> list(x ** 3 for x in range(5)) [0, 1, 8, 27, 64]

--迭代器(迭代就是循環)

能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator

可迭代對象有:

一類是集合數據類型,如list,tuple,dict,set,str等

一類是generator,包括生成器和帶yield的generator function

這些能夠直接做用於for 循環的對象統稱爲可迭代對象:Iterable

可是必須能夠被next() 函數調用病不斷返回下一個值! 的  可迭代對象,纔是迭代器

# 判斷下列數據類型是可迭代對象or迭代器
s='hello'     #字符串是可迭代對象,但不是迭代器
l=[1,2,3,4]     #列表是可迭代對象,但不是迭代器
t=(1,2,3)       #元組是可迭代對象,但不是迭代器
d={'a':1}        #字典是可迭代對象,但不是迭代器
set={1,2,3}     #集合是可迭代對象,但不是迭代器 # *************************************
f=open('test.txt') #文件是可迭代對象,是迭代器

能夠用isinstance 判斷

print(isinstance(s,Iterator))     #判斷是否是迭代器
print(isinstance(s,Iterable))       #判斷是否是可迭代對象

listdictstrIterable變成Iterator可使用iter()函數

>>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True

 

Python3的for循環本質上就是經過不斷調用next()函數實現的,例如:

for x in [1, 2, 3, 4, 5]: pass

實際上徹底等價於

# 首先得到Iterator對象:
it = iter([1, 2, 3, 4, 5]) # 循環:
while True: try: # 得到下一個值:
        x = next(it) except StopIteration: # 遇到StopIteration就退出循環
        break

 

感謝:https://www.cnblogs.com/wj-1314/p/8490822.html

相關文章
相關標籤/搜索