Python 進階之路 (七) 隱藏的神奇寶藏:探祕Collections
神奇的collections
大家好,今天想和大家分享一個Python裡面非常棒的模快: Collections
該模組實現了專門的容器資料型別,為Python的通用內建容器提供了替代方案,如果對原始碼感興趣的朋友們可以在 Lib/collections/__init__.py 路徑下找到
基於我目前的學習經驗,以下幾種型別用的很多:
- defaultdict (dict子類呼叫工廠函式來提供缺失值)
- counter (用於計算可雜湊物件的dict子類)
- deque (類似於列表的容器,可以從兩端操作)
- namedtuple (用於建立具有命名欄位的tuple子類的工廠函式)
好啦,看到什麼工廠函式,可雜湊物件,容器這些詞彙不要慌,我第一次看是懵逼併直接跳過的,然而後來發現根本不需要理解,如果大家感興趣可以自己去查詢,這裡還是老樣子,通過大量例項來一個個講解就好啦!
defaultdict
基礎概念
“defaultdict”是在名為“collections”的模組中定義的容器。它需要一個函式(預設工廠)作為其引數。預設情況下設定為“int”,即0.如果鍵不存在則為defaultdict,並返回並顯示預設值。
我用人話解釋一下:其實就是一個查不到key值時不會報錯的dict
應用例項
首先我們來看一個用正常dict的例子,如果我們建立了一個叫person的字典,裡面儲存的key值為name,age,如果這時候嘗試呼叫person['city'],會丟擲KeyError錯誤,因為沒有city這個鍵值:
person = {'name':'xiaobai','age':18} print ("The value of key'name' is : ",person['name']) print ("The value of key'city' is : ",person['city']) Out: The value of key'name' is :xiaobai Traceback (most recent call last): File "C:\Users\E560\Desktop\test.py", line 17, in <module> print ("The value of key'city' is : ",person['city']) KeyError: 'city'
現在如果我們用defaultdict再試試呢?
from collections import defaultdict person = defaultdict(lambda : 'Key Not found') # 初始預設所有key對應的value均為‘Key Not Found’ person['name'] = 'xiaobai' person['age'] = 18 print ("The value of key'name' is : ",person['name']) print ("The value of key'adress' is : ",person['city']) Out:The value of key'name' is :xiaobai The value of key'adress' is :Key Not found
大家可以發現,這次沒有問題了,其實最根本的原因在於當我們建立defaultdict時,首先傳遞的引數是所有key的預設value值,之後我們新增name,age進去的時候才會有所改變,當我們最終查詢時,如果key存在,那就輸出對應的value值,如果不存在,就會輸出我們事先規定好的值‘Key Not Found’
除此之外外,我們還可以利用defaultdict建立時,傳遞引數為所有key預設value值這一特性,實現一些其他的功能,比如:
from collections import defaultdict d = defaultdict(list) d['person'].append("xiaobai") d['city'].append("paris") d['person'].append("student") for i in d.items(): print(i) Out: ('person', ['xiaobai', 'student']) ('city', ['paris'])
一個道理,我們預設所有key對應的是一個list,自然就可以在賦值時使用list的append方法了。再比如下面這個例子:
from collections import defaultdict food = ( ('jack', 'milk'), ('Ann', 'fruits'), ('Arham', 'ham'), ('Ann', 'soda'), ('jack', 'dumplings'), ('Ahmed', 'fried chicken'), ) favourite_food = defaultdict(list) for n, f in food: favourite_food[n].append(f) print(favourite_food) Out:defaultdict(<class 'list'>, {'jack': ['milk', 'dumplings'], 'Ann': ['fruits', 'soda'], 'Arham': ['ham'], 'Ahmed': ['fried chicken']})
道理和上面差不多,這裡大家可以自己拓展,展開想象,相信可能在某個時刻可以用的上defaultdict這個容器
counter
基礎概念
Counter是dict的子類。因此,它是一個無序集合,其中元素及其各自的計數儲存為字典。這相當於其他語言的bag或multiset。
我的理解就是一個計數器,返回一個字典,key就是出現的元素,value就是該元素出現的次數
應用例項
計數器沒啥可說的,還能幹啥,計數唄!
from collections import Counter count_list = Counter(['B','B','A','B','C','A','B','B','A','C'])#計數list print (count_list) count_tuple = Counter((2,2,2,3,1,3,1,1,1))#計數tuple print(count_tuple) Out:Counter({'B': 5, 'A': 3, 'C': 2}) Counter({1: 4, 2: 3, 3: 2})
Counter一般不會用於dict和set的計數,因為dict的key是唯一的,而set本身就不能有重複元素
現在我們也可以直接把在defaultdict例子中用過food元組拿來計數:
from collections import Counter food = ( ('jack', 'milk'), ('Ann', 'fruits'), ('Arham', 'ham'), ('Ann', 'soda'), ('jack', 'dumplings'), ('Ahmed', 'fried chicken'), ) favourite_food_count = Counter(n for n,f in food)#統計name出現的次數 print(favourite_food_count) Out: Counter({'jack': 2, 'Ann': 2, 'Arham': 1, 'Ahmed': 1})
deque
基礎概念
在我們需要在容器兩端的更快的新增和移除元素的情況下,可以使用deque.
我的個人理解是deque就是一個可以兩頭操作的容器,類似list但比列表速度更快
應用例項
deque的方法有很多,很多操作和list類似,也支援切片
from collections import deque d = deque() d.append(1) d.append(2) d.append(3) print(len(d)) print(d[0]) print(d[-1]) Out: 3 1 3
deque最大的特點在於我們可以從兩端操作:
d = deque([i for i in range(5)]) print(len(d)) # Output: 5 d.popleft()# 刪除並返回最左端的元素 # Output: 0 d.pop()# 刪除並返回最右端的元素 # Output: 4 print(d) # Output: deque([1, 2, 3]) d.append(100)# 從最右端新增元素 d.appendleft(-100) # 從最左端新增元素 print(d) # Output: deque([-100, 1, 2, 3, 100])
除了這些deque的方法實在太多了,比如我再舉幾個常用的例子,首先我們定義一個deque時可以規定它的最大長度,deque和list一樣也支援extend方法,方便列表拼接,但是deque提供雙向操作:
from collections import deque d = deque([1,2,3,4,5], maxlen=9)#設定總長度不變 d.extendleft([0])# 從左端新增一個list d.extend([6,7,8])# 從右端拓展一個list print(d) Out:deque([0, 1, 2, 3, 4, 5, 6, 7, 8], maxlen=9)
現在d已經有9個元素了,而我們規定的maxlen=9,這個時候如果我們從左邊新增元素,會自動移除最右邊的元素,反之也是一樣:
d.append(100) print(d) d.appendleft(-100) print(d) Out: deque([1, 2, 3, 4, 5, 6, 7, 8, 100], maxlen=9) deque([-100, 1, 2, 3, 4, 5, 6, 7, 8], maxlen=9)
deque還有很多其他的用法,大家根據各自的需要去自己尋寶吧!
namedtuple
基礎概念
名稱元組。大家一看名字就會感覺和tuple元組有關,沒錯,我認為它是元組的強化版
namedtuple可以將元組轉換為方便的容器。使用namedtuple,我們不必使用整數索引來訪問元組的成員。
我覺得可以把namedtuple 視為 不可變的 字典
應用 例項
首先,讓我們先回顧一下普通元組是如何訪問成員的:
person = ('xiaobai', 18) print(person[0]) out:xiaobai
現在我們看看namedtuple(名稱元組)的強大之處:
from collections import namedtuple Person = namedtuple('Person', 'name age city')# 類似於定義class xiaobai = Person(name="xiaobai", age=18, city="paris") # 類似於新建物件 print(xiaobai) Out:Person(name='xiaobai', age=18, city='paris')
我們建立namedtuple時非常像定義一個class,這裡Person好比是類名,第二個引數就是namedtuple的值的名字了,我感覺很像class裡的屬性,不過這裡不用加逗號分離,下面讓我們看看如何訪問namedtuple的成員:
print(xiaobai.name) print(xiaobai.age) print(xiaobai.city) out:xiaobai 18 paris
"爽啊,爽死了",郭德綱看到這裡不禁讚歎
這種無限接近class呼叫屬性的方式還是非常不錯的,在一些實際場景很有用。
最後還有一點千萬不要忘了,我們不能修改namedtuple裡的值:
xiaobai.name = 'laobai' Out:Traceback (most recent call last): File "C:\Users\E560\Desktop\test.py", line 5, in <module> xiaobai.name = 'laobai' AttributeError: can't set attribute
總結
今天為大家簡單介紹了collections的一些基礎容器型別,我把它成為寶藏感覺還是不過分的,因為這些容器在真正使用場景中的確非常有用,而且我發現很多教程大多不會提到,衷心希望可以幫到大家,如果我哪裡介紹錯誤或者遺漏,希望大家留言指出,讓我們一起進步!