Python 標準ライブラリ collections コンテナデータ型
Publish date: 2021-03-28
組み込み型 list、 tuple、 dict、 set以外で使えるコンテナのデータ型です。
概要
以下のようなコンテナデータ型・関数が用意されています。
- namedtuple() 名前付きタプル
- Counter キーによる数え上げ
- ChainMap 複数の辞書から1つの辞書を構成
- OrderedDict 追加順序ありの辞書
- defaultdict 既定値ありの辞書
- deque 両端で出し入れするキュー
- UserDict 辞書のサブクラス作成用
- UserList リストのサブクラス作成用
- UserString 文字列のサブクラス作成用
namedtuple() 名前付きタプル
namedtupleの定義
from collections import namedtuple
# namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)
# typename : タプルにつける名称
# field_names : フィールド名のリスト、または、空白やカンマ区切りの文字列
# rename : 名称の自動修正を行う場合True
# defaults : デフォルト値のiterable
# module : __module__属性
PersonRecord = namedtuple('PersonRecord', ['name', 'age', 'departmnet'])
PersonRecord = namedtuple('PersonRecord', 'name, age, departmnet')
PersonRecord = namedtuple('PersonRecord', 'name age departmnet')
raname=True
で識別子として使えない名称が自動で置換される。
typename = namedtuple('typename', 'namedummy, def, namedummy, int', rename=True)
typename._fields # => ('namedummy', '_1', '_2', 'int')
defaults
で既定値を設定できる。
DefautlSample = namedtuple('DefautlSample', 'f1, f2, f3', defaults=['X', 1])
DefautlSample._field_defaults # => {'f2': 'X', 'f3': 1}
ds = DefautlSample('A')
ds # = > DefautlSample(f1='A', f2='X', f3=1)
namedtupleの作成は、位置で引数を渡すほか、
辞書を**
で展開して引数として渡すこともできる。
PersonRecord = namedtuple('PersonRecord', 'name, age, departmnet')
dic = {'name':'Taro', 'age':22, 'departmnet':'A1'}
pr = PersonRecord(**dic)
pr # => PersonRecord(name='Taro', age=22, departmnet='A1')
namedtupleの使い方と要素へのアクセス
PersonRecord = namedtuple('PersonRecord', ['name', 'age', 'departmnet'])
item = PersonRecord('Taro', 22, departmnet='A1')
item # => PersonRecord(name='Taro', age=22, departmnet='A1')
name , age , departmnet = item
name # => 'Taro'
age # => 22
departmnet # => 'A1'
item[0] # => 'Taro'
item[1] # => 22
item[2] # => 'A1'
item.name # => 'Taro'
item.age # => 22
item.departmnet # => 'A1'
getattr(item , 'name') # => 'Taro'
getattr(item , 'age') # => 22
getattr(item , 'departmnet') # => 'A1'
namedtupleの属性・メソッド
# _fields フィールド名のタプル
item._fields # => ('name', 'age', 'departmnet')
# _asdict() 辞書の取得
item._asdict() # => {'name': 'Taro', 'age': 22, 'departmnet': 'A1'}
# _make(iterable) インスタンスの生成
instance = PersonRecord._make(['Jiro', 20, 'B1'])
instance #=> PersonRecord(name='Jiro', age=20, departmnet='B1')
# _replace(**kwargs) 書き換えたタプルの取得
instance._replace(age=19) # => PersonRecord(name='Jiro', age=19, departmnet='B1')
namedtupleの使用例(SQLite)
DB接続等のマッピングで便利に使える。
import sqlite3
from contextlib import closing
from collections import namedtuple
PersonRecord = namedtuple('PersonRecord', 'name, age, departmnet')
with closing(sqlite3.connect('sample.db')) as con:
cursor = con.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS person
(name TEXT, age INTEGER, departmnet TEXT)
""")
cursor.execute("DELETE FROM person ;")
cursor.execute("INSERT INTO person VALUES ('Taro', 25, 'A1' );")
cursor.execute("INSERT INTO person VALUES ('Jirp', 20, 'B1' );")
cursor.execute("INSERT INTO person VALUES ('Hanako', 22, 'A2' );")
con.commit()
cursor.execute("SELECT name, age, departmnet from person;")
for person in map(PersonRecord._make, cursor.fetchall()):
print(person)
print(person.name, person.age, person.departmnet)
con.close()
Counter キーによる数え上げ
Counterの定義
from collections import Counter
c = Counter()
c # => Counter()
c = Counter('ababcbacabacbacada')
c #=> Counter({'a': 8, 'b': 5, 'c': 4, 'd': 1})
c = Counter(['AAA', 'ABA', 'ABA', 'AAA', 'AAA', 'BAA', 'AAA', 'AAA', 'ABA'])
c # => ounter({'AAA': 5, 'ABA': 3, 'BAA': 1})
c = Counter({'key1': 5, 'key2': 7})
c # => Counter({'key1': 5, 'key2': 7})
c = Counter(key1=5, key2=7)
c # => Counter({'key1': 5, 'key2': 7})
Counterの属性・メソッド
c = Counter('ababcada')
# elements キーのカウント数繰り返し
list(c.elements()) # => ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'd']
# most_common([n]) カウント上位のキーと数のタプル
c.most_common(3) # => [('a', 4), ('b', 2), ('c', 1)]
# subtract([iterable-or-mapping]) 差分
c1 = Counter(a=3, b=2, c=3)
c2 = Counter(a=1, b=2, c=5)
c1.subtract(c2)
c1 # => Counter({'a': 2, 'b': 0, 'c': -2})
Counterの使い方
c = Counter('ababcada')
c # => Counter({'a': 4, 'b': 2, 'c': 1, 'd': 1})
# Counterはdictのサブクラス
isinstance(c , dict) # => True
c.values() # => dict_values([4, 2, 1, 1]) カウントのリスト
sum(c.values()) # => 8 カウントの合計
c.update({'a':2,'c':1}) # updateはカウントの加算
c # => Counter({'a': 6, 'b': 2, 'c': 2, 'd': 1})
ChainMap 複数の辞書から1つの辞書を構成
ChainMapの定義
from collections import ChainMap
map1 = {'k1':'value1_1', 'k2':'value2_1', 'k3':'value3_1'}
map2 = {'k2':'value2_2', 'k4':'value4_2'}
cm = ChainMap(map2, map1)
ChainMapの属性・メソッド
map1 = {'k1':'value1_1', 'k2':'value2_1', 'k3':'value3_1'}
map2 = {'k2':'value2_2', 'k4':'value4_2'}
cm = ChainMap(map2, map1)
# maps マッピングの一覧
cm.maps
# => {'k2': 'value2_2', 'k4': 'value4_2'}, {'k1': 'value1_1', 'k2': 'value2_1', 'k3': 'value3_1'}]
# リストは全ての世代のキー
list(cm) # => ['k1', 'k2', 'k3', 'k4']
for k in cm:
print(f'cm["{k}"]={cm[k]}')
# =>
# cm["k1"]=value1_1
# cm["k2"]=value2_2
# cm["k3"]=value3_1
# cm["k4"]=value4_2
# new_child(m=None) 新しい辞書を追加したChsainMapを取得
map3 = {'k3':'value3_3', 'k5':'value5_3'}
cm_new = cm.new_child(map3)
for k in cm_new:
print(f'cm_new["{k}"]={cm_new[k]}')
# =>
# cm_new["k1"]=value1_1
# cm_new["k2"]=value2_2
# cm_new["k3"]=value3_3
# cm_new["k4"]=value4_2
# cm_new["k5"]=value5_3
# parents 最初の辞書以外の全辞書を持ったChainMap
cm_new.parents == cm # => True
for k in cm_new.parents:
print(f'cm_new.parents["{k}"]={cm_new.parents[k]}')
# =>
# cm_new.parents["k1"]=value1_1
# cm_new.parents["k2"]=value2_2
# cm_new.parents["k3"]=value3_1
# cm_new.parents["k4"]=value4_2
# 更新前の辞書
cm_new.maps
# =>
# [{'k3': 'value3_3', 'k5': 'value5_3'},
# {'k2': 'value2_2', 'k4': 'value4_2'},
# {'k1': 'value1_1', 'k2': 'value2_1', 'k3': 'value3_1'}]
# 値の更新
cm_new['k2'] = 'value2_new'
cm_new['k5'] = 'value5_new'
del cm_new['k3']
# 辞書の更新は最新の辞書について行われる
cm_new.maps
# =>[{'k5': 'value5_new', 'k2': 'value2_new'},
# {'k2': 'value2_2', 'k4': 'value4_2'},
# {'k1': 'value1_1', 'k2': 'value2_1', 'k3': 'value3_1'}]
OrderedDict 追加順序ありの辞書
OrderedDictの定義
from collections import OrderedDict
od = OrderedDict({'a':1, 'b':2, 'c':3})
OrderedDictの属性・メソッド
from collections import OrderedDict
od = OrderedDict({'a':1, 'b':2, 'c':3})
od['e'] = 4
od['f'] = 5
od # => OrderedDict([('a', 1), ('b', 2), ('c', 3), ('e', 4), ('f', 5)])
isinstance(od, dict) # => True
# popitem(last=True) last:TrueならLIFO、falseならFIFO
pi = od.popitem()
pi # => ('f', 5)
od # => OrderedDict([('a', 1), ('b', 2), ('c', 3), ('e', 4)])
# move_to_end(key, last=True) キーの項目を辞書の最初から最後に移動
od.move_to_end('c')
od #=> OrderedDict([('a', 1), ('b', 2), ('e', 4), ('c', 3)])
od.move_to_end('b',last=False)
od # => OrderedDict([('b', 2), ('a', 1), ('e', 4), ('c', 3)])
list(reversed(od)) # => ['c', 'e', 'a', 'b']
defaultdict 既定値ありの辞書
defaultdictの定義
from collections import defaultdict
# defaultdict([default_factory[, ...]]) デフォルト値を設定し初期化
dd = defaultdict() # => defaultdict(None, {})
dd = defaultdict(int) # => defaultdict(int, {})
dd = defaultdict(list) # => defaultdict(list, {})
defaultdictの使用例
dd = defaultdict(int) # => defaultdict(list, {})
for s in 'acababcaa':
dd[s] += 1
dd # => defaultdict(int, {'a': 5, 'c': 2, 'b': 2})
deque 両端で出し入れするキュー
dequeの定義
from collections import deque
# deque([iterable[, maxlen]])
deq = deque() # => deque([])
deq = deque('aabacab') # => deque(['a', 'a', 'b', 'a', 'c', 'a', 'b'])
deq = deque([1, 3, 2, 5, 1]) # => deque([1, 3, 2, 5, 1])
deq = deque([1, 3, 2, 5, 1], 3) # => eque([2, 5, 1])
dequeの属性・メソッド
deq = deque() # => deque([])
# append(x) 右側追加
deq.append(1) # => deque([1])
deq.append(2) # => deque([1, 2])
# appendleft(x) 左側追加
deq.appendleft(3) # => deque([3, 1, 2])
# extend(iterable) 右にイテレータの要素を追加
deq.extend([1, 1, 1, 3, 2]) # => deque([3, 1, 2, 1, 1, 1, 3, 2])
# extendleft(iterable) 左にイテレータの要素を追加
deq.extendleft([3, 2]) # => deque([2, 3, 3, 1, 2, 1, 1, 1, 3, 2])
# insert(i, x) 挿入
deq.insert(5, 3) # => deque([2, 3, 3, 1, 2, 3, 1, 1, 1, 3, 2])
# count(x) 要素の数え上げ
deq.count(1) # => 4
# index(x[, start[, stop]]) 位置の取得
deq.index(1) # => 3
deq.index(1, 4) # => 6
# deq.index(1, 1, 2) # => ValueError: 1 is not in deque
# copy() シャローコピー
copy_deq = deq.copy()
copy_deq # => deque([2, 3, 3, 1, 2, 3, 1, 1, 1, 3, 2])
# pop() 右から取得
item = deq.pop()
item # => 2
deq # => deque([2, 3, 3, 1, 2, 3, 1, 1, 1, 3])
# popleft() 左から取得
item = deq.popleft()
item # => 2
deq # => deque([3, 3, 1, 2, 3, 1, 1, 1, 3])
# remove(value) 最初に現れる要素の除外
deq.remove(1)
deq # => deque([3, 3, 2, 3, 1, 1, 1, 3])
# reverse() 順番の反転
deq.reverse()
deq # => deque([3, 1, 1, 1, 3, 2, 3, 3])
# rotate(n=1) 右にローテーション(マイナスで左)
deq.rotate(2)
deq # => deque([3, 3, 3, 1, 1, 1, 3, 2])
# maxlen 最大長の制限
deq.maxlen # => None
# clear()
deq.clear()
deq # => deque([])