1. 程式人生 > 實用技巧 >什麼是容器和可迭代的物件(及生成器和迭代器)

什麼是容器和可迭代的物件(及生成器和迭代器)

#!/usr/bin/python3
# -*- coding:utf-8 -*-
#Author:qika


'''
一. 容器
容器是一種把多個元素組織在一起的資料結構,容器中的元素可以逐個地迭代獲取,
可以用in, not in關鍵字判斷元素是否包含在容器中。通常這類資料結構把所有的元素儲存在記憶體中
(也有一些特例,並不是所有的元素都放在記憶體,比如迭代器和生成器物件)在Python中,常見的容器物件有:
list, deque...
set, frozensets(不可變集合)...
dict, defaultdict, OrderedDict, Counter...
tuple, namedtuple...
str
容器的概念就像一個盒子,可以往裡面裝東西.當它可以用來詢問某個元素是否包含在其中時,
那麼這個物件就可以認為是一個容器,比如 list,set,tuples都是容器物件:


assert 1 in [1, 2, 3]      # lists
assert 4 not in [1, 2, 3]
assert 1 in {1, 2, 3}      # sets
assert 4 not in {1, 2, 3}
assert 1 in (1, 2, 3)      # tuples
assert 4 not in (1, 2, 3)

詢問某元素是否在dict中用dict的中key:

d = {1: 'foo', 2: 'bar', 3: 'qux'}
assert 1 in d
assert 'foo' not in d  # 'foo' 不是dict中的元素
詢問某substring是否在string中:
s = 'foobar'
assert 'b' in s
assert 'x' not in s
assert 'foo' in s
儘管絕大多數容器都提供了某種方式來獲取其中的每一個元素,但這並不是容器本身提供的能力,
而是可迭代物件賦予了容器這種能力,當然並不是所有的容器都是可迭代的,
比如:Bloom filter,雖然Bloom filter可以用來檢測某個元素是否包含在容器中,
但是並不能從容器中獲取其中的每一個值,因為Bloom filter壓根就沒把元素儲存在容器中,
而是通過一個雜湊函式對映成一個值儲存在陣列中。
二. 可迭代物件(iterable)
大部分物件都是可迭代,只要實現了__iter__方法的物件就是可迭代的。 __iter__方法會返回迭代器(iterator)本身,例如: lst = [1,2,3] lst.__iter__() <listiterator object at 0x7f97c549aa50> Python提供一些語句和關鍵字用於訪問可迭代物件的元素,比如for迴圈、列表解析、邏輯操作符等。 判斷一個物件是否是可迭代物件: from collections import Iterable # 只匯入Iterable方法 isinstance('abc', Iterable) >>True isinstance(1, Iterable) >>False isinstance([], Iterable) >>True 這裡的isinstance()函式用於判斷物件型別。 可迭代物件一般都用for迴圈遍歷元素,也就是能用for迴圈的物件都可稱為可迭代物件。 例如,遍歷列表: lst = [1, 2, 3] for i in lst: print i '''
#列表推導式 # a = [x for x in range(10)] # b = [x**2 for x in range(10)] # print(a) # print(b) #生成器 #可以理解為一種資料型別,自動實現迭代器協議 #生成器建立:2種方式 #第一種:(x for x in range(10)) #第二種:yield ''' #第一種方式: a = (x for x in range(10)) print(a)#會列印<generator object <genexpr> at 0x0000000001DE2E60>,即生成器物件 a1=a.__next__() #通過內建的方法__next__()進行獲取值 print(a1)#列印值。但是始終都是預設獲取的值是:0 #因此,如果想要迭代獲取範圍內所有的值,都是通過next()來獲取 next(a)#獲取第一次,獲取的值為1 next(a)#值為2 #我臨時插入做點其他的事情 print(“我臨時做其他的事情”) next(a)#值為3--->> 這就是生成器的作用,雖然中途插入做了其他事情,但是我後面還是可以接著繼續使用生成器函式
#第二種方式: def test(): print("one") yield 1 #yield 等同於 return 1 print("two") yield 2 #yield 等同於 return 2 t = test() print(t)#<generator object test at 0x0000000002132EB8> 會打印出這是個生成器物件 #獲取值,該怎麼做? print(next(t))#列印一次,預設獲取第一個值:one,1 print(next(t))#列印第二次,獲取值:two,2 #另:如果像上面那樣僅僅使用next(t)不加print,那麼就只會執行函式內的內容,而不會管yield #此時就不會管print出yield的內容(所以yield就如同函式的return) # next(t)#獲取第一次,值:one # next(t)#獲取第二次,值:two #總結:----------------------------------- #在呼叫生成器的過程中, # 每次遇到yield時函式會暫停並儲存打印出當前所有的執行資訊並返回yield的值。 #並在下一次執行next()方法時又繼續執行後面的 ''' #send()方法 ''' def test(): print("one") count=yield 1 print(count) print("two") yield 2 t = test() #注意!!!使用send()傳值時,需要有“變數”接收 t.send(None)#使用send時,第一次傳值只能使用None,如同next(t) # print(t) t.send("aaa") '''
############################################ ############################################## #迭代器


#定義: #生成器都是迭代器(而迭代器不一定是生成器 ) #python中的內部工具(如for迴圈,sum,min,max函式等)基於迭代器協議訪問物件。 #作用: # 1、省記憶體,如果使用列表,計算值時會一次獲取所有值,那麼就會佔用更多的記憶體。 # 而迭代器則是一個接一個計算,只能向前,不能反覆 # 2、使程式碼更通用、更簡單。 # 3、惰性機制 #如何判斷是不是迭代器? #需滿足兩個條件:1、有iter方法。2、有next方法 #例項: #迭代器的物件內部定義了一個__iter__()方法 l=[1,2,3,4,5,6] d=iter(l) #即相等於 l.__iter__() print(next(d))#迭代列印l列表內的值:1 print(next(d))#迭代列印l列表內的值:2 print(next(d))#迭代列印l列表內的值:3 #--->>從上可見,在“滿足有iter方法時,有next方法存在”時,就是一個迭代器物件了!!! #-->>那麼如何通過for迴圈來遍歷一個迭代器物件??? # 用while迴圈模擬for迴圈機制 li=[1,2,3,4,5,6] diedai_l = li.__iter__() while True: try: print(diedai_l.__next__()) except StopIteration: print("迭代完畢,迴圈終止") break """ for迴圈時: 1呼叫可迭代物件的iter方法並返回一個迭代器物件 2不斷呼叫迭代器物件的next方法 3處理stopiteration這個報錯資訊(因為超出邊界了,超出了範圍,會自動停止) """ #最後,如何通過程式碼判斷是否為迭代器物件呢? #--->>通過isinstance()方法來判斷 from collections import Iterator print(isinstance(1,list))#會打印出False,因為1不是列表,即:可迭代物件 li=[1,2,3,4,5,6] print(isinstance(li,list))#判斷li列表,是否為list可迭代物件-->>結果會打印出true