PS:本文Python 3.6.4,更高Python版本有更豐富的功能
文章目錄
簡介
這個模塊提供Python標準數據類型dict
, list
, set
, 和 tuple
的替代選擇:
函數或類 | 功能 |
---|---|
namedtuple() |
創建命名元組子類的工廠函數 |
deque |
類似list,實現了在兩端快速添加(append)和彈出(pop) |
ChainMap |
類似dict,將多個映射集合到一個視圖裏面 |
Counter |
dict的子類,提供了可哈希對象的計數功能 |
OrderedDict |
dict的子類,保存了添加的順序 |
defaultdict |
dict的子類,提供一個工廠函數,爲字典查詢提供一個默認值 |
UserDict |
封裝dict對象,簡化dict子類化 |
UserList |
封裝list對象,簡化list子類化 |
UserString |
封裝string對象,簡化string子類化 |
常用的有:
Counter
- 計數器defaultdict
- 帶默認值字典OrderedDict
- 有序字典deque
- 雙端隊列ChainMap
- 鏈式映射namedtuple()
- 命名元組
引入包
from collections import *
ChainMap 鏈映射
ChainMap用於組合多個字典
基本用法
d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}
chain_map = ChainMap(d1, d2)
print(chain_map.maps)
# [{'a': 1, 'b': 2}, {'b': 3, 'c': 4}]
print(chain_map['a'])
# 1
有多個值時,取最開始遇到的
print(chain_map['b']) # 取最開始的值
# 2
改變了對應字典,ChainMap也會變
d2['c'] = 5
print(chain_map['c']) # 改變了d2,chain_map也會變
# 5
keys()
, values()
, items()
獲取鍵值對
# 獲取鍵值對
print(list(chain_map.keys()))
print(list(chain_map.values()))
print(list(chain_map.items())) # 使用方法與dict類似
# ['c', 'b', 'a']
# [5, 2, 1]
# [('c', 5), ('b', 2), ('a', 1)]
new_child()
添加新字典
# 添加新字典
d3 = {'b': 4, 'd': 5, 'e': 6}
new_chain_map = chain_map.new_child(d3) # d3會被置頂
print(new_chain_map)
print(new_chain_map['b']) # d3爲最開始的值
# ChainMap({'b': 4, 'd': 5, 'e': 6}, {'a': 1, 'b': 2}, {'b': 3, 'c': 4})
# 4
深度寫和刪除
ChainMap只能刪除第一條字典有的鍵,只能更新第一條字典有的鍵
try:
del new_chain_map['a']
except Exception as e:
print(e) # 只能刪除第一條字典有的鍵
new_chain_map['c'] = 6 # 只能更新第一條字典有的鍵
print(new_chain_map)
# "Key not found in the first mapping: 'a'"
# ChainMap({'b': 4, 'd': 5, 'e': 6, 'c': 6}, {'a': 1, 'b': 2}, {'b': 3, 'c': 5})
實現深度寫和刪除
class DeepChainMap(ChainMap):
'深度寫和刪除的ChainMap'
def __setitem__(self, key, value):
for mapping in self.maps:
if key in mapping:
mapping[key] = value
return
self.maps[0][key] = value
def __delitem__(self, key):
for mapping in self.maps:
if key in mapping:
del mapping[key]
return
raise KeyError(key)
測試
deep_chain_map = DeepChainMap({'b': 4, 'd': 5, 'e': 6}, {'a': 1, 'b': 2}, {'b': 3, 'c': 5})
print(deep_chain_map)
try:
del deep_chain_map['a'] # 深度刪除
except Exception as e:
print(e)
deep_chain_map['c'] = 6 # 深度寫
print(deep_chain_map)
# DeepChainMap({'b': 4, 'd': 5, 'e': 6}, {'a': 1, 'b': 2}, {'b': 3, 'c': 5})
# DeepChainMap({'b': 4, 'd': 5, 'e': 6}, {'b': 2}, {'b': 3, 'c': 6})
實例
讓命令行參數 > 環境變量 > 默認值
import os
import argparse
from collections import ChainMap
defaults = {
'COLOR': 'red',
'USERNAME': 'Administrator',
'JAVA_HOME': 'C:\Java\jdk1.8.0_201'
}
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--COLOR')
parser.add_argument('-u', '--USERNAME')
parser.add_argument('-j', '--JAVA_HOME')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}
chain_map = ChainMap(command_line_args, os.environ, defaults) # 命令行參數 > 環境變量 > 默認值
print(chain_map['COLOR'])
print(chain_map['USERNAME'])
print(chain_map['JAVA_HOME'])
直接運行
red
XerCis
C:\Program Files\Java\jdk1.8.0_201
帶參數運行:python test.py -j "D:\Program Files\Java\jdk1.8.0_201"
red
XerCis
D:\Program Files\Java\jdk1.8.0_201
Counter 計數器
基本用法
Counter是dict的子類
l = '1112233456'
cnt = Counter(l)
print(cnt)
print(cnt['1']) #'1'出現的次數
# Counter({'1': 3, '2': 2, '3': 2, '4': 1, '5': 1, '6': 1})
# 3
elements()
所有元素
print(list(cnt.elements())) # 按出現順序返回所有元素,忽略0和負數
# ['1', '1', '1', '2', '2', '3', '3', '4', '5', '6']
most_common()
最常見元素
print(cnt.most_common(4)) # 按常見程度和出現順序排序
# [('1', 3), ('2', 2), ('3', 2), ('4', 1)]
數學操作
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
print(c + d) # 相加
print(c - d) # 相減
print(c & d) # 交集,同min(c[x], d[x])
print(c | d) # 並集,同max(c[x], d[x])
# Counter({'a': 4, 'b': 3})
# Counter({'a': 2})
# Counter({'a': 1, 'b': 1})
# Counter({'a': 3, 'b': 2})
實例
統計列表字典中不同字段的數目,如統計性別
from collections import Counter
x = [
{'name': '張三', 'gender': 'male'},
{'name': '李四', 'gender': 'male'},
{'name': '王五', 'gender': 'female'},
]
print(Counter([i['gender'] for i in x]))
# Counter({'male': 2, 'female': 1})
deque 雙端隊列
deque,念“deck”,double-ended queue的簡稱,雙端隊列
可高效在雙端添加(append)和彈出(pop),時間複雜度都是O(1)
基本用法
可用for…in遍歷
d = deque('def')
for x in d:
print(x) # 遍歷
# d
# e
# f
append()
右插
appendleft()
左插
d.append('g') #右插
d.appendleft('c') #左插
print(d)
# deque(['c', 'd', 'e', 'f', 'g'])
pop()
右彈
popleft()
左彈
print(d.pop()) # 右彈
print(d.pop()) # 右彈
print(d)
# g
# c
# deque(['d', 'e', 'f'])
print(d[0]) # 第一個
print(d[-1]) # 最後一個
print(list(d)) # 全部元素
print(list(reversed(d))) # 翻轉
# d
# f
# ['d', 'e', 'f']
# ['f', 'e', 'd']
extend()
右擴展
extendleft()
左擴展
d.extend('ghi') # 右擴展
print(d)
d.extendleft('cba') # 左擴展
print(d)
# deque(['d', 'e', 'f', 'g', 'h', 'i'])
# deque(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
實例
類似Unix的 tail
功能
def tail(filename, n=10):
'返回一個文件的最後n行'
with open(filename) as f:
return deque(f, n)
with open('a.txt', mode='w') as f:
for i in range(100):
f.write(str(i)+'\n')
print(tail('a.txt'))
# deque(['90\n', '91\n', '92\n', '93\n', '94\n', '95\n', '96\n', '97\n', '98\n', '99\n'], maxlen=10)
defaultdict 帶默認值字典
使用普通dict
時Key不存在會拋出異常,使用defaultdict
時Key不存在會返回一個默認值
defaultdict
其他用法和dict
無異
基本用法
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list) # 默認值爲列表
for k, v in s:
d[k].append(v)
print(d)
# defaultdict(<class 'list'>, {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]})
推薦閱讀:Python setdefault和defaultdict誰更快?
namedtuple() 命名元組
命名元組賦予每個位置一個含義,提供可讀性和自文檔性。它們可以用於任何普通元組,並添加了通過名字獲取值的能力
基本用法
Point = namedtuple('Point', ['x', 'y']) # Point是一個命名元組,第一個位置是x,第二個是y
p = Point(11, 22) # 用位置或關鍵字參數實例化一個點
print(p)
print(p[0], p[1]) # 下標訪問
print(p.x, p.y) # 名字訪問
# Point(x=11, y=22)
# 11 22
# 11 22
_make()
從已有序列創建一個實例
t = [11, 22]
t = Point._make(t) # 從已有序列創建一個實例
print(t)
# Point(x=11, y=22)
# 和元組一樣,不能直接修改值
try:
t[0] = 22
except Exception as e:
print(e)
try:
t.x = 22
except Exception as e:
print(e)
print(t._replace(x=22)) # 返回新的
print(t) # 原來的不變
_fields
列出字段名
Point = namedtuple('Point', ['x', 'y'])
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields + Color._fields)
print(Pixel(11, 22, 128, 255, 0))
# Pixel(x=11, y=22, red=128, green=255, blue=0)
實例
- CSV
employees.csv
name,age,title,department,paygrade
a,22,elementary,development,1
b,25,intermediate,sales,2
c,30,high,personnel,3
import csv
from collections import namedtuple
EmployeeRecord = namedtuple("EmployeeRecord", "name, age, title, department, paygrade")
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv"))):
print(emp.name, emp.title)
# name title
# a elementary
# b intermediate
# c high
- sqlite3
import os
import sqlite3
from collections import namedtuple
database = "companydata.db"
# 創建SQLite數據庫
if os.path.exists(database):
os.remove(database)
connection = sqlite3.connect(database)
cursor = connection.cursor()
cursor.execute("CREATE TABLE 'employees' ('name' text, 'age' text, 'title' text, 'department' text, 'paygrade' text)")
cursor.execute("INSERT INTO 'employees' VALUES ('a','22','elementary','development', '1')")
cursor.execute("INSERT INTO 'employees' VALUES ('b','25','intermediate','sales', '2')")
cursor.execute("INSERT INTO 'employees' VALUES ('c','30','high','personnel', '3')")
connection.commit()
connection.close()
# 從數據庫導入
connection = sqlite3.connect(database)
cursor = connection.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
# name title
# a elementary
# b intermediate
# c high
OrderedDict 有序字典
OrderedDict
會記住插入順序
Python 3.7中,dict
會保持插入順序,因此 OrderedDict
在Python 3.7+中不再重要