collections,Python開發(fā)更高效

介紹

collections 模塊是 Python 標準庫的一部分,提供了多種增強的數(shù)據(jù)類型,包括 namedtuple、deque、Counter、OrderedDict、defaultdictChainMap

這些數(shù)據(jù)類型比內(nèi)置類型更靈活高效,適用于特定場景。掌握和合理使用這些數(shù)據(jù)結(jié)構,你會發(fā)現(xiàn)日常開發(fā)效率會非常高。

常見數(shù)據(jù)結(jié)構

namedtuple

namedtuple 是 Python collections 模塊中的一個工廠函數(shù),用于創(chuàng)建具有命名字段的不可變序列。它提供了類似于元組的性能和內(nèi)存效率,同時可以通過名稱訪問其元素,從而提高代碼的可讀性可維護性

下面通過一段關于操作 地理坐標(Geolocation) 的代碼來詳細說明:如何創(chuàng)建 namedtuple、訪問其元素,以及 namedtuple 的方法和屬性。

# 導入
from collections import namedtuple

# 定義 namedtuple 類型 Geo
Geo = namedtuple('Geo', ['latitude', 'longitude'])

# 創(chuàng)建幾個 Geo 實例
a_geo = Geo(39.9042, 116.4074)
b_geo = Geo(31.2304, 121.4737)
c_geo = Geo(23.1291, 113.2644)

# 打印地理坐標
print(f"a_geo: {a_geo.latitude}, {a_geo.longitude}")  # 輸出: a_geo: 39.9042, 116.4074
print(f"b_geo: {b_geo.latitude}, {b_geo.longitude}")  # 輸出: b_geo: 31.2304, 121.4737
print(f"c_geo: {c_geo.latitude}, {c_geo.longitude}")  # 輸出: c_geo: 23.1291, 113.2644

# 使用 _make() 方法創(chuàng)建實例
data = [22.5431, 114.0579]
d_geo = Geo._make(data)
print(f"d_geo: {d_geo.latitude}, {d_geo.longitude}")  # 輸出: d_geo: 22.5431, 114.0579

# 使用 _asdict() 方法將 namedtuple 轉(zhuǎn)換為字典
a_dict = a_geo._asdict()
print(a_dict)  # 輸出: OrderedDict([('latitude', 39.9042), ('longitude', 116.4074)])

# 使用 _replace() 方法更新實例
updated_a = a_geo._replace(latitude=39.913818)
print(updated_a)  # 輸出: Geo(latitude=39.913818, longitude=116.4074)

# 查看字段名稱
print(Geo._fields)  # 輸出: ('latitude', 'longitude')

應用場景

  • 數(shù)據(jù)記錄:用于表示數(shù)據(jù)庫查詢結(jié)果或日志記錄。
  • 配置項:用于保存配置信息,例如服務器配置或應用程序設置。
  • 數(shù)據(jù)傳輸:用于定義消息格式,方便序列化和傳輸數(shù)據(jù)。

deque

deque 是一個雙端隊列,它支持從兩端進行高效的添加和刪除操作。

基本使用

deque 支持從兩端進行快速的添加和刪除操作。

from collections import deque

# 創(chuàng)建一個空的 deque
my_deque = deque()

# 創(chuàng)建包含元素的 deque
my_deque_with_data = deque([1, 2, 3, 4, 5])

# 添加元素到 deque 的右端
my_deque.append(6)

# 添加元素到 deque 的左端
my_deque.appendleft(0)

# 從 deque 的右端刪除元素
right_element = my_deque.pop()

# 從 deque 的左端刪除元素
left_element = my_deque.popleft()

deque 的方法和屬性

  • append(item): 將元素添加到 deque 的右端。
  • appendleft(item): 將元素添加到 deque 的左端。
  • pop(): 從 deque 的右端刪除并返回一個元素。
  • popleft(): 從 deque 的左端刪除并返回一個元素。
  • extend(iterable): 將可迭代對象中的元素添加到 deque 的右端。
  • extendleft(iterable): 將可迭代對象中的元素添加到 deque 的左端。
  • rotate(n): 將 deque 向右循環(huán)移動 n 步(如果 n 是負數(shù),則向左移動)。
  • clear(): 清空 deque 中的所有元素。
  • count(item): 返回 deque 中等于 item 的元素個數(shù)。
  • reverse(): 將 deque 中的元素逆序排列。
  • copy(): 返回 deque 的淺拷貝。

我們來用這些方法實現(xiàn)一個基于LRU策略(最近最少使用)的緩存類來慢慢感受下deque的高級玩法:

from collections import deque

class LRUCache:
    def __init__(self, capacity):
        self.capacity = capacity
        self.cache = deque(maxlen=capacity)  # 使用 deque 作為緩存
        self.cache_map = {}  # 用于存儲鍵值對的映射關系

    def get(self, key):
        if key in self.cache_map:
            # 如果鍵存在于緩存中,則將其移到緩存隊列的右端(最近使用)
            self.cache.remove(key)
            self.cache.append(key)
            return self.cache_map[key]
        else:
            return -1

    def put(self, key, value):
        if key in self.cache_map:
            # 如果鍵已存在于緩存中,則更新值并將其移到緩存隊列的右端(最近使用)
            self.cache.remove(key)
            self.cache.append(key)
            self.cache_map[key] = value
        else:
            if len(self.cache) == self.capacity:
                # 如果緩存已滿,則移除最左端(最久未使用)的鍵值對
                removed_key = self.cache.popleft()
                del self.cache_map[removed_key]
            # 將新的鍵值對添加到緩存隊列的右端(最近使用)
            self.cache.append(key)
            self.cache_map[key] = value

    def clear(self):
        # 清空緩存隊列和映射關系
        self.cache.clear()
        self.cache_map.clear()

    def extend(self, iterable):
        # 將可迭代對象中的元素添加到緩存隊列的右端(最近使用)
        self.cache.extend(iterable)

    def __repr__(self):
        return str(self.cache)

    
# 測試示例
cache = LRUCache(3)
cache.put(1, 'a')
cache.put(2, 'b')
cache.put(3, 'c')
print(cache)  # 輸出: deque([1, 2, 3], maxlen=3)

cache.put(4, 'd')
print(cache)  
# 輸出: deque([2, 3, 4], maxlen=3)
# 因為元素超過了3個,所以淘汰了元素 1,添加保留了元素 4

cache.clear()
print(cache)  # 輸出: deque([], maxlen=3)

cache.extend([4, 5, 6])
print(cache)  # 輸出: deque([4, 5, 6], maxlen=3)

應用場景

  • 隊列和棧:用于實現(xiàn)隊列(FIFO)和棧(LIFO)等數(shù)據(jù)結(jié)構。
  • 緩存:用于實現(xiàn)LRU(Least Recently Used)緩存算法,保留最近訪問的元素,丟棄最舊的元素。
  • 任務調(diào)度:用于實現(xiàn)異步任務調(diào)度器,管理任務隊列并支持快速的入隊和出隊操作。

Counter

常用于計數(shù)可哈希對象。

基本使用

from collections import Counter

# 創(chuàng)建一個 Counter 對象
my_counter = Counter([1, 1, 2, 3, 3, 3, 4, 4, 5])
# 獲取元素的計數(shù)
count_of_3 = my_counter[3]  # 輸出: 3

# 更新計數(shù)
my_counter[3] += 1

# 添加新元素
my_counter[6] = 1

方法和屬性

  • elements(): 返回一個迭代器,包含 Counter 對象中的所有元素,重復次數(shù)與計數(shù)相等。
  • most_common(n): 返回前 n 個最常見的元素及其計數(shù),以列表形式返回。
  • subtract(iterable): 從 Counter 對象中減去可迭代對象中的元素的計數(shù)。
  • update(iterable): 將可迭代對象中的元素添加到 Counter 對象中。
  • clear(): 清空 Counter 對象中的所有元素。
  • copy(): 返回 Counter 對象的淺拷貝。
  • items(): 返回 Counter 對象的鍵值對。
  • keys(): 返回 Counter 對象的鍵。
  • values(): 返回 Counter 對象的值。
  • most_common(n): 返回前 n 個最常見的元素及其計數(shù)。

你會發(fā)現(xiàn)Counter有部分類似dict字段的方法,這是因為Counter類繼承了dict

通過實現(xiàn)一個打工人出生地的統(tǒng)計計數(shù)器來感受下Counter類的使用:

from collections import Counter

# 模擬一堆大學生的出生地數(shù)據(jù)
birthplaces = ['Beijing', 'Shanghai', 'Guangzhou', 'Beijing', 'Shanghai']
# 創(chuàng)建 Counter 對象統(tǒng)計出生地
birthplace_counter = Counter(birthplaces)
# 獲取出生地為上海的學生人數(shù)
shanghai_students = birthplace_counter['Shanghai']
# 更新計數(shù),添加更多學生的出生地數(shù)據(jù)
more_birthplaces = ['Beijing', 'Shanghai', 'Chongqing', 'Shanghai', 'Shenzhen']
birthplace_counter.update(more_birthplaces)
# 獲取出生地為北京的學生人數(shù)
beijing_students = birthplace_counter['Beijing']
# 統(tǒng)計有哪些地區(qū)
uniq_birthplaces = list(birthplace_counter.keys())
# 獲取計數(shù)最多的 2 個出生地及其計數(shù)
top_birthplaces = birthplace_counter.most_common(2)
# 從統(tǒng)計中減去一部分出生地數(shù)據(jù)
subtract_birthplaces = ['Beijing', 'Shanghai']
birthplace_counter.subtract(subtract_birthplaces)
# 獲取計數(shù)最少的 1 個出生地及其計數(shù)
bottom_birthplace = birthplace_counter.most_common()[-1]
# 清空計數(shù)器
birthplace_counter.clear()

# 輸出結(jié)果
print("出生地為上海的學生人數(shù):", shanghai_students)  # 出生地為上海的學生人數(shù): 2
print("出生地為北京的學生人數(shù):", beijing_students)  # 出生地為北京的學生人數(shù): 3
print("有哪些出生地:", uniq_birthplaces)
# 有哪些出生地: ['Beijing', 'Shanghai', 'Guangzhou', 'Chongqing', 'Shenzhen']
print("計數(shù)最多的 2 個出生地:", top_birthplaces)  
# 計數(shù)最多的 2 個出生地: [('Shanghai', 4), ('Beijing', 3)]
print("計數(shù)最少的 1 個出生地:", bottom_birthplace)  # 計數(shù)最少的 1 個出生地: ('Shenzhen', 1)
print("清空后的計數(shù)器:", birthplace_counter)  # 清空后的計數(shù)器: Counter()

應用場景

  • 文本處理:用于統(tǒng)計單詞出現(xiàn)次數(shù)或字符出現(xiàn)次數(shù)。
  • 數(shù)據(jù)分析:用于統(tǒng)計數(shù)據(jù)集中各個元素的出現(xiàn)頻率。
  • 詞頻統(tǒng)計:用于生成詞云、繪制頻率分布圖等。

OrderedDict

OrderedDict 是一個有序字典,它可以記住元素的添加順序。雖然 Python3.7 以后版本的dict也改成了有序字典,但基于可讀性和兼容性,依然使用推薦OrderedDict

基本使用

from collections import OrderedDict

# 創(chuàng)建一個空的 OrderedDict
empty_ordered_dict = OrderedDict()
# 創(chuàng)建包含鍵值對的 OrderedDict
ordered_dict = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 添加鍵值對到 OrderedDict
ordered_dict['d'] = 4
# 刪除鍵值對
del ordered_dict['a']
# 獲取鍵對應的值
value_of_b = ordered_dict['b']

OrderedDict 的方法和屬性

  • move_to_end(key, last=True): 將指定鍵移動到有序字典的最后或最開始,默認移到最后。
  • popitem(last=True): 彈出有序字典中的最后一個鍵值對或第一個鍵值對,默認彈出最后一個。
  • clear(): 清空有序字典中的所有鍵值對。
  • copy(): 返回有序字典的淺拷貝。
  • keys(): 返回有序字典中的所有鍵。
  • values(): 返回有序字典中的所有值。
  • items(): 返回有序字典中的所有鍵值對。

OrderedDictCounter一樣,也是繼承了dict一樣

應用場景

  • 配置文件:用于保存配置信息,并保持配置項的順序與文件中的順序一致。
  • 歷史記錄:用于記錄用戶操作歷史,并保持操作的順序。
  • 命令行參數(shù):用于保存命令行參數(shù),并保持參數(shù)的順序與輸入順序一致。

defaultdict

defaultdict 是一種字典的子類,它允許給每個鍵一個默認值,從而避免了在訪問不存在的鍵時引發(fā) KeyError 異常,這在實際開發(fā)中非常有用

基本使用

from collections import defaultdict

# 創(chuàng)建一個默認字典,指定默認值為 int 類型的 0
default_dict = defaultdict(int)
# 添加鍵值對到 defaultdict
default_dict['a'] = 1
# 獲取鍵對應的值,如果鍵不存在,則返回默認值, int 默認返回0
value_of_b = default_dict['b']
print(value_of_b)  # 輸出:0
# 刪除鍵值對
# 當然刪除不存在的鍵值對還是會觸發(fā) KeyError 的
del default_dict['a']

# 創(chuàng)建一個默認字典,指定默認值為 list 類型的空列表
default_dict_list = defaultdict(list)
print(default_dict_list["a"])  # 輸出:[]

defaultdict 的方法和屬性

  • default_factory: 默認工廠函數(shù),用于生成默認值。
  • copy(): 返回 defaultdict 對象的淺拷貝。
  • keys(): 返回 defaultdict 對象中的所有鍵。
  • values(): 返回 defaultdict 對象中的所有值。
  • items(): 返回 defaultdict 對象中的所有鍵值對。

defaultdict也是繼承了dict,所以很多方法都很類似,區(qū)別在于defaultdict允許給每個鍵一個默認值

重點說說defualtdict中的default_factory:

default_factory除了設置為某種類型(如 intlist 等)外,還可以將其設置為函數(shù),以便在需要時動態(tài)生成默認值(任何對象:數(shù)值、字符串、類實例等),從而實現(xiàn)更靈活的功能。

下面則是使用這種方法構造默認采集配置:

from collections import defaultdict


# 定義默認的爬蟲配置參數(shù)
def default_config():
    return {
        'user_agent': 'Mozilla/5.0 ***',
        'timeout': 10,
        'retry': 3,
        'headers': {'Accept': 'text/html,application/json'},
        'proxies': None
    }

# 創(chuàng)建一個 defaultdict,并指定默認值的生成函數(shù)為 default_config
crawler_config = defaultdict(default_config)

print(crawler_config["baidu"]["timeout"])  # 輸出:10
print(crawler_config["weixin"]["timeout"])  # 輸出:10

應用場景

  • 計數(shù)器初始化:用于創(chuàng)建計數(shù)器字典,并設置默認計數(shù)值為0。
  • 數(shù)據(jù)分組:用于分組數(shù)據(jù)集,并將缺失的組初始化為空列表或其他默認值。
  • 統(tǒng)計分析:用于統(tǒng)計數(shù)據(jù)集中各類別的頻率,并將缺失的類別初始化為0。

ChainMap

用于將多個字典或映射組合在一起形成單個視圖,適用于需要處理多個映射的情況。

方法與屬性

  • new_child(m=None): 創(chuàng)建一個新的 ChainMap 對象,將參數(shù) m(字典或映射)添加到鏈的開頭。
  • parents: 返回一個包含所有父映射的新 ChainMap 對象。
  • maps: 返回一個包含所有映射的列表。
  • copy(): 返回 ChainMap 對象的淺拷貝。

用法

下面舉個配置合并的例子來說明下用法:

from collections import ChainMap

# 定義三個模塊的配置信息
module1_config = {'timeout': 10, 'retry': 3}
module2_config = {'user_agent': 'Mozilla/5.0', 'proxies': 1}
module3_config = {'headers': {'Accept': 'text/html'}}

# 使用 ChainMap 合并多個模塊的配置
combined_config = ChainMap(module1_config, module2_config, module3_config)

# 獲取所有映射
print("所有映射:")
print(combined_config.maps)

# 獲取父映射(去除最后一個映射)
parent_maps = combined_config.parents
print("\n父映射:")
for parent_map in parent_maps:
    print(parent_map)

# 獲取指定鍵的值
print("\n獲取指定鍵的值:")
print("timeout:", combined_config['timeout'])
print("user_agent:", combined_config['user_agent'])

# 添加新的映射
new_module_config = {'timeout': 20, 'retry': 5}
combined_config = combined_config.new_child(new_module_config)
print("\n添加新的映射后的配置信息:")
print(combined_config)

print(combined_config['proxies'])

應用場景

  • 配置管理:用于合并多個配置源(如全局配置、用戶配置、默認配置)并提供統(tǒng)一的配置視圖。
  • 命名空間:用于將多個命名空間(如全局命名空間、模塊命名空間、局部命名空間)組合在一起,形成單個命名空間。
  • 上下文管理器:用于管理多個上下文,并提供統(tǒng)一的上下文視圖,使得上下文的嵌套和覆蓋更加靈活。

使用優(yōu)勢

  • 更具表達性collections中的數(shù)據(jù)結(jié)構通常比內(nèi)置的數(shù)據(jù)結(jié)構更具表達性,能夠更清晰地表達程序的意圖,代碼也會簡單很多。
  • 更高級的功能collections中的數(shù)據(jù)結(jié)構提供了一些額外的功能,這些功能在特定的使用場景下非常有用。
  • 性能優(yōu)勢:在某些特定的操作中,collections中的數(shù)據(jù)結(jié)構可能比內(nèi)置數(shù)據(jù)結(jié)構性能更好。
  • 可擴展性:如果你的程序需要更多的功能,collections模塊提供了一些非常有用的數(shù)據(jù)結(jié)構,可以滿足更廣泛的需求。
  • 標準化:使用collections中的數(shù)據(jù)結(jié)構能夠讓你的代碼更加標準化和易于理解。

如果你覺得本文有幫助到你,非常期待得到你的支持和鼓勵;
如果有其他問題或補充,歡迎評論區(qū)留言交流。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容