Python3でコレクションモジュールを使用する方法
序章
Python 3には、タプル、辞書、リストなど、多数の組み込みデータ構造があります。 データ構造は、データを整理して保存する方法を提供します。 The collections モジュールは、データ構造を効率的に入力および操作するのに役立ちます。
このチュートリアルでは、コレクションモジュールの3つのクラスを実行して、タプル、辞書、およびリストの操作を支援します。 使用します namedtuples 名前付きフィールドを持つタプルを作成するには、 defaultdict 辞書に情報を簡潔にグループ化するため、および deque リストのようなオブジェクトのいずれかの側に要素を効率的に追加します。
このチュートリアルでは、主に、架空の水族館に魚を追加したり、水族館から魚を削除したりするときに変更する必要のある魚の在庫を扱います。
前提条件
このチュートリアルを最大限に活用するには、タプル、ディクショナリ、およびリストのデータ型について、構文とそれらからデータを取得する方法の両方についてある程度理解しておくことをお勧めします。 必要な背景情報については、次のチュートリアルを確認できます。
タプルへの名前付きフィールドの追加
Pythonタプルは、不変または不変の順序付けられた要素のシーケンスです。 タプルは、列データを表すために頻繁に使用されます。 たとえば、CSVファイルの行やSQLデータベースの行などです。 水族館は、一連のタプルとして魚の在庫を追跡する場合があります。
個々の魚のタプル:
("Sammy", "shark", "tank-a")
このタプルは、3つの文字列要素で構成されています。
このタプルはいくつかの点で便利ですが、各フィールドが何を表しているかを明確に示していません。 実際には、要素 0 名前、要素です 1 種であり、要素 2 貯蔵タンクです。
魚のタプルフィールドの説明:
| 名前 | 種族 | タンク |
|---|---|---|
| サミー | 鮫 | 短歌 |
この表は、タプルの3つの要素のそれぞれが明確な意味を持っていることを明確にしています。
namedtuple から collections モジュールを使用すると、タプルの各要素に明示的な名前を追加して、Pythonプログラムでこれらの意味を明確にすることができます。
使ってみよう namedtuple 魚のタプルの各要素に明確に名前を付けるクラスを生成するには、次のようにします。
from collections import namedtuple
Fish = namedtuple("Fish", ["name", "species", "tank"])
from collections import namedtuple Pythonプログラムにアクセスを許可します namedtuple 工場機能。 The namedtuple() 関数呼び出しは、名前にバインドされているクラスを返します Fish. The namedtuple() 関数には2つの引数があります:新しいクラスの目的の名前 "Fish" および名前付き要素のリスト ["name", "species", "tank"].
使用できます Fish 以前の魚のタプルを表すクラス:
sammy = Fish("Sammy", "shark", "tank-a")
print(sammy)
このコードを実行すると、次の出力が表示されます。
OutputFish(name='Sammy', species='shark', tank='tank-a')
sammy を使用してインスタンス化されます Fish クラス。 sammy は、明確に名前が付けられた3つの要素を持つタプルです。
sammyのフィールドには、名前または従来のタプルインデックスを使用してアクセスできます。
print(sammy.species)
print(sammy[1])
これら2つを実行すると print 呼び出し、次の出力が表示されます。
Outputshark
shark
アクセス .species の2番目の要素にアクセスするのと同じ値を返します sammy を使用して [1].
使用する namedtuple から collections モジュールは、タプルの重要なプロパティ(不変で順序付けられている)を維持しながら、プログラムを読みやすくします。
加えて namedtuple ファクトリ関数は、のインスタンスにいくつかの追加メソッドを追加します Fish.
._ asdict()を使用して、インスタンスを辞書に変換します。
print(sammy._asdict())
実行すると print、次のような出力が表示されます。
Output{'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}
呼び出し .asdict() の上 sammy 3つのフィールド名のそれぞれを対応する値にマッピングする辞書を返します。
3.8より古いPythonバージョンでは、この行の出力が少し異なる場合があります。 たとえば、 OrderedDict ここに示されている単純な辞書の代わりに。
注: Pythonでは、先頭にアンダースコアが付いているメソッドは通常「プライベート」と見なされます。 namedtuple によって提供される追加のメソッド( _asdict(), ._make(), ._replace()、など)、ただし、はパブリックです。
辞書にデータを収集する
多くの場合、Python辞書でデータを収集すると便利です。 defaultdict から collections モジュールは、辞書内の情報をすばやく簡潔に組み立てるのに役立ちます。
defaultdict 決して上げません KeyError. キーが存在しない場合、 defaultdict 代わりにプレースホルダー値を挿入して返します。
from collections import defaultdict
my_defaultdict = defaultdict(list)
print(my_defaultdict["missing"])
このコードを実行すると、次のような出力が表示されます。
Output[]
defaultdict をスローする代わりに、プレースホルダー値を挿入して返します KeyError. この場合、プレースホルダー値をリストとして指定しました。
対照的に、通常の辞書は KeyError 不足しているキーについて:
my_regular_dict = {}
my_regular_dict["missing"]
このコードを実行すると、次のような出力が表示されます。
OutputTraceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'missing'
通常の辞書 my_regular_dict を上げる KeyError 存在しないキーにアクセスしようとしたとき。
defaultdict 通常の辞書とは動作が異なります。 上げる代わりに KeyError 不足しているキーについて、 defaultdict 引数なしでプレースホルダー値を呼び出して、新しいオブジェクトを作成します。 この場合 list() 空のリストを作成します。
架空の水族館の例を続けて、水族館の在庫を表す魚のタプルのリストがあるとしましょう。
fish_inventory = [
("Sammy", "shark", "tank-a"),
("Jamie", "cuttlefish", "tank-b"),
("Mary", "squid", "tank-a"),
]
水族館には3匹の魚がいます。これらの3つのタプルには、名前、種、貯蔵タンクが記載されています。
私たちの目標は、水槽ごとに在庫を整理することです。各水槽にいる魚のリストを知りたいのです。 言い換えれば、マップする辞書が必要です "tank-a" に ["Sammy", "Mary"] と "tank-b" に ["Jamie"].
使用できます defaultdict 魚を水槽ごとにグループ化するには:
from collections import defaultdict
fish_inventory = [
("Sammy", "shark", "tank-a"),
("Jamie", "cuttlefish", "tank-b"),
("Mary", "squid", "tank-a"),
]
fish_names_by_tank = defaultdict(list)
for name, species, tank in fish_inventory:
fish_names_by_tank[tank].append(name)
print(fish_names_by_tank)
このコードを実行すると、次の出力が表示されます。
Outputdefaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})
fish_names_by_tank として宣言されています defaultdict デフォルトでは挿入 list() 投げる代わりに KeyError. これにより、すべてのキーが fish_names_by_tank を指します list、自由に電話できます .append() 各戦車のリストに名前を追加します。
defaultdict 予期しない可能性を減らすので、ここであなたを助けます KeyErrors. 予期しないものを減らす KeyErrors これは、プログラムをより明確に、より少ない行で記述できることを意味します。 より具体的には、 defaultdict イディオムを使用すると、すべてのタンクの空のリストを手動でインスタンス化する必要がなくなります。
それなし defaultdict、 for ループ本体は次のようになっている可能性があります。
...
fish_names_by_tank = {}
for name, species, tank in fish_inventory:
if tank not in fish_names_by_tank:
fish_names_by_tank[tank] = []
fish_names_by_tank[tank].append(name)
(代わりに)通常の辞書だけを使用する defaultdict)は、 for ループ本体は常に与えられたものの存在をチェックする必要があります tank の fish_names_by_tank. それを確認した後でのみ tank にすでに存在しています fish_names_by_tank、またはで初期化されたばかり []、魚の名前を付けてもいいですか。
defaultdict 辞書を埋めるときにボイラープレートコードを削減するのに役立ちます。 KeyError.
コレクションのいずれかの側に要素を効率的に追加するためのdequeの使用
Pythonリストは、変更可能または変更可能な順序付けられた要素のシーケンスです。 Pythonは一定時間でリストに追加できますが(リストの長さは追加にかかる時間に影響しません)、リストの先頭への挿入は遅くなる可能性があります。リストが大きくなるにつれて、かかる時間は長くなります。
Big O表記に関しては、リストへの追加は一定時間です O(1) 手術。 対照的に、リストの先頭への挿入は、 O(n) パフォーマンス。
注:ソフトウェアエンジニアは、「BigO」表記と呼ばれるものを使用して手順のパフォーマンスを測定することがよくあります。 入力のサイズが手順の実行にかかる時間に影響を与えない場合、一定時間で実行されると言われます。 O(1) (「ビッグオーオブ1」)。 上で学んだように、Pythonは一定の時間パフォーマンスでリストに追加できます。 O(1).
入力のサイズが、プロシージャの実行にかかる時間に直接影響する場合があります。 たとえば、Pythonリストの先頭に挿入すると、リストに含まれる要素が多いほど実行速度が遅くなります。 BigO表記は文字を使用します n 入力のサイズを表します。 これは、Pythonリストの先頭にアイテムを追加すると、「線形時間」または O(n) (「nのビッグO」)。
一般に、 O(1) 手順はより高速です O(n) 手順。
Pythonリストの先頭に挿入できます。
favorite_fish_list = ["Sammy", "Jamie", "Mary"]
# O(n) performance
favorite_fish_list.insert(0, "Alice")
print(favorite_fish_list)
次のように実行すると、次のような出力が表示されます。
Output['Alice', 'Sammy', 'Jamie', 'Mary']
The .insert(index, object) リストのメソッドを使用すると、 "Alice" の初めに favorite_fish_list. ただし、特に、リストの先頭に挿入すると、 O(n) パフォーマンス。 の長さとして favorite_fish_list 成長するにつれて、リストの最初に魚を挿入する時間は比例して増加し、ますます長くかかります。
deque (「デッキ」と発音)から collections moduleはリストのようなオブジェクトであり、シーケンスの最初または最後に一定の時間でアイテムを挿入できます(O(1)) パフォーマンス。
の先頭にアイテムを挿入します deque:
from collections import deque
favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
# O(1) performance
favorite_fish_deque.appendleft("Alice")
print(favorite_fish_deque)
このコードを実行すると、次の出力が表示されます。
Outputdeque(['Alice', 'Sammy', 'Jamie', 'Mary'])
インスタンス化できます deque 既存の要素のコレクション、この場合は3つのお気に入りの魚の名前のリストを使用します。 呼び出し favorite_fish_dequeの appendleft メソッドを使用すると、コレクションの先頭にアイテムを挿入できます。 O(1) パフォーマンス。 O(1) パフォーマンスとは、アイテムを最初に追加するのにかかる時間を意味します favorite_fish_deque たとえ成長しなくても favorite_fish_deque 数千または数百万の要素があります。
注: deque リストよりも効率的にシーケンスの先頭にエントリを追加します。 deque リストよりも効率的にすべての操作を実行するわけではありません。 たとえば、のランダムなアイテムにアクセスする deque もっている O(n) パフォーマンスは向上しますが、リスト内のランダムなアイテムにアクセスすると、 O(1) パフォーマンス。 使用する deque コレクションのいずれかの側から要素をすばやく挿入または削除することが重要な場合。 時間パフォーマンスの完全な比較は、Pythonのwikiで入手できます。
結論
The collections モジュールはPython標準ライブラリの強力な部分であり、データを簡潔かつ効率的に処理できます。 このチュートリアルでは、 collections を含むモジュール namedtuple, defaultdict、 と deque.
ここから、コレクションモジュールのドキュメントを使用して、他の利用可能なクラスとユーティリティについて詳しく知ることができます。 Python全般の詳細については、Python3チュートリアルシリーズでコーディングする方法をご覧ください。