Pythonのdictは辞書型 データの作成や値の指定方法

Pythonのdict型

Pythonのdict配列

dictは辞書型と呼ばれるPythonの型で、以下のように記述できます。

b = {'one': 1, 'two': 2, 'three': 3}

記述方法はいくつかありますが、上記方法がprint文で変数を表示したときの表記と同じになるため、わかりやすいと思います。

print文で変数bを表示するとこうなります。

$ python3
Python 3.6.9 (default, Jan 26 2021, 15:33:00)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> print( b )
{'one': 1, 'two': 2, 'three': 3}

関連 Pythonのprint

上記の「>>>」が出てくるモードは、コマンドラインから「python3」と実行すると始まるインタラクティブモードです。

なお、以下のa~fの記述方法は全て同一の結果になります。

>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> f = dict({'one': 1, 'three': 3}, two=2)
>>> a == b == c == d == e == f
True

上記の「one」「two」「three」はkeyと呼ばれ、値にアクセスするために指定可能です。dict型のオブジェクトbのtwoというキーの要素にアクセスするには、以下のように記述します。

>>> print( b['two'] )
2

参考 組み込み型 — Python 3.10.6 ドキュメント

Pythonのdictの使い方

Pythonのdictの使い方

dictのgetメソッドは、KeyErrorにならない

dict型では、存在しないキーを指定するとKeyErrorというエラーが発生します。以下は、b[‘four’]を指定しようとしてKeyErrorが発生した例です。

>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> print( b['four'] )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'four'
<br>

キー指定して値を取得するためにgetメソッドを使うと、キーが存在しなくてもエラーになりません。代わりにNone(デフォルト値)が返されます。

>>> print( b.get('four') )
None
>>> print( b.get('three') )
3

KeyErrorを発生させたくない(exceptなどで例外処理を書きたくない)場合は、getメソッドを使いましょう。

何も指定しなければ、キーが存在しない場合に返す値はNone。getメソッドの第二引数指定で、キーが存在しない場合に返す値を指定できます。

例えば、以下のように指定すると、「No Key」が返り値となります。

>>> print( b.get('four', 'No Key') )
No Key

dict型のキー(key)が存在したら取得する

dict型に指定のキーが存在するかどうかチェックしたいケースでは、inを使います。

>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> if( 'one' in b ):
... print( "one exists" )
...
one exists
>>> if( 'four' in b ):
... print( "four exists" )
...
>>>

上記の例では、「one」というキーは存在するけど、「four」というキーは存在しないということになります。

ちょっと気になるのは、この書き方ってキーだけが対象になってるの?値の方にマッチしてたらTrueになるんじゃない?例えば、上記の例では「1 in b」がTrueになるんじゃない?ってこと。

試してみました。

>>> if( 1 in b ):
... print( "1 exists" )
...
>>>
>>> 1 in b
False

あー、たしかにキーだけが対象になっているっぽいですね。疑って悪かった。

dict型に追加

dict型に値を追加するには、単に要素に値を代入すればOK。存在しないキーなら新規追加になるし、存在するキーなら上書き更新になります。

>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> b
{'one': 1, 'two': 2, 'three': 3}
>>> b['four']=4
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> b['four']='four'
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 'four'}

おー、気が利いてる仕様。しかし、「存在しないなら新規追加」「存在したら上書きしない」という動きにしたいときは、setdefault()メソッドを使います。

>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> # キーfourは存在しないので新規挿入
>>> b.setdefault('four',4)
4
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> # キーfourが存在する状態で使うと、上書き更新されない
>>> b.setdefault('four',0)
4
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>>

おー、これも気が利いてる動きをするメソッド。ただ、名前が直感的じゃないなぁデフォルト値を設定するみたいな名前だけど、noupdate_insert()みたいな名前の方がわかりやすかったかも。

dict型を更新(update)

dict型を更新するには、上記のsetdefault()メソッドのほか、update()メソッドが使えます。

>>> b={'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> b.update(five=5,six=6)
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6}
>>> b.update(one=0,two=0,six=0)
>>> b
{'one': 0, 'two': 0, 'three': 3, 'four': 4, 'five': 5, 'six': 0}

既にキーが存在する場合は更新、キーがない場合は追加になります。指定方法がちょっと特殊で、引数としてカンマ区切りで、キー名=値,キー名=値…と指定するか、別のdict型のみ指定できます。

以下は、dict型のオブジェクトbに、別のdict型オブジェクトcを指定して、update()メソッドを実行したサンプルです。

>>> b={'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> c={'five':5, 'six':6}
>>> b.update(c)
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6}

「キーが存在する場合は更新、キーが存在しない場合は何もしない」という処理をしたいケースでは、if文とキー存在チェック(キー in 辞書型オブジェクト)とsetdefault()を組み合わせるしかないかな…あまりないケースだとは思いますが。

dict型の削除

dict型オブジェクトから要素を削除するには、delを使います。

以下のサンプルは、dict型オブジェクトbから、「four」というキーを持つ要素を削除する例です。

>>> b={'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> del b['four']
>>> b
{'one': 1, 'two': 2, 'three': 3}

なお、存在しないキーを指定するとKeyErrorが発生します。

>>> del b['five']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'five'

dict型のコピー(copy)

dict型のコピーをするには、copy()メソッドを使います。

以下は、dict型オブジェクトbをcにコピーした後、cのみ更新(キーfiveを追加)した例です。

>>> b={'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> c=b.copy()
>>> c
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> c['five']=5
>>> c
{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5}
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 4}

当然ですが、cに加えた変更はbには影響していないのが確認できます。

ところが、単に代入(=)を使うと、一見コピーできたように見えて、実体は同じものを指すことになってしまうので注意が必要です。

>>> b={'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> c=b
>>> c
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> c['five']=5
>>> c
{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5}
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5}

オブジェクトcを更新したはずが、bの方も変更されてしまっています。けっこう気づきにくいバグになる可能性がありますね。

dict型のソート(sort)

dict型のソートには、sortedを使います。sortedは元のオブジェクトは更新せずに、新たなソート済みオブジェクトを生成するメソッド。

単純に「dict型にはsort()メソッドが用意されていない。代わりにsorted()メソッドを使う」とおぼえておけば良いと思います。

キーでソートするには、以下のようにします。

>>> b={'five': 5, 'six': 6, 'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> sorted(b.items())
[('five', 5), ('four', 4), ('one', 1), ('six', 6), ('three', 3), ('two', 2)]

あー…キーでソートすると、キー名がアルファベット順に並ぶので、このケースではバラバラになっちゃいますね。値の方でソートするにはこのようにします。

>>> sorted(b.items(),key=lambda x:x[1])
[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5), ('six', 6)]

初見だと何やってるのかさっぱりですね…。とりあえず、決まった書き方として覚えておくといいんじゃないでしょうか。

ソート順を逆にするには、引数にreverse=Trueを指定します。

>>> sorted(b.items(),key=lambda x:x[1],reverse=True)
[('six', 6), ('five', 5), ('four', 4), ('three', 3), ('two', 2), ('one', 1)]

dict型をjson型に変換

dict型をjson型に変換するには、jsonライブラリを使います。

以下は、dict型オブジェクトbをjson形式で標準出力に出力した例(json.dumps)です。引数にindent指定することで、インデントを入れることも可能。

>>> b={'five': 5, 'six': 6, 'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> json.dumps(b)
'{"five": 5, "six": 6, "one": 1, "two": 2, "three": 3, "four": 4}'
>>> json.dumps(b,indent=2)
'{n "five": 5,n "six": 6,n "one": 1,n "two": 2,n "three": 3,n "four": 4n}'

ファイルに出力するには、json.dumpを使います。

>>> b={'five': 5, 'six': 6, 'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> file1='./output.json'
>>> json_fp=open(file1,mode="w")
>>> json.dump(b,json_fp,indent=2)
>>> json_fp.close()

カレントディレクトリに、output.jsonというファイルが生成されます。

$ cat output.json
{
"five": 5,
"six": 6,
"one": 1,
"two": 2,
"three": 3,
"four": 4
}

Pythonのdictの作成

dict型の初期化

dict型の初期化は、{}で要素を囲うことで記述できます。また、空のdict型はdict()で生成可能です。

>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> b
{'one': 1, 'two': 2, 'three': 3}
>>> c=dict()
>>> c
{}

キーが決まっていて、値を全て同じ値にしたいという場合は、fromkeys()メソッドが使えます。

>>> keylist=['one','two','three']
>>> b=dict.fromkeys(keylist,0)
>>> b
{'one': 0, 'two': 0, 'three': 0}

キーのリストと値のリストをいわゆる「ガッチャンコ」してdict型にするにはzipを使います。

>>> keylist=['one','two','three']
>>> valuelist=[1,2,3]
>>> d=dict(zip(keylist,valuelist))
>>> d
{'one': 1, 'two': 2, 'three': 3}

おお、これ便利。

ネットで見る限りでは、郵便番号と住所とか、市外局番と市町村名なんかの組み合わせが便利そうでした。

dict型をforループで初期化

初期値を同一の値じゃなくて、徐々に増やしていきたいとか、forループに連動する形にしたいときは、こんな感じで記述します。

以下は、keylistのキーに対して、ループで増分していく変数iを値に設定した例。

>>> b=dict()
>>> keylist=['one','two','three','four','five']
>>> for (i,k) in zip(range(1,6),keylist):
... b[k]=i
...
>>> b
{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5}

dict型の内包表記

dict型でも内包表記ができます。

>>> b={x:x*2 for x in range(5)}
>>> b
{0: 0, 1: 2, 2: 4, 3: 6, 4: 8}

内包表記はlist型で頻繁に使う小技で、一見してわかりにくいけど、処理が高速になるというもの。しかし、dict型でキーが数字になっても嬉しくないし、イマイチ使い所がないかも…。

関連 Pythonのlist

あとは、キーが決まってて、同じ値にしたいときにも一応使えるかな…。

>>> keylist
['one', 'two', 'three', 'four', 'five']
>>> b={k:'0' for k in keylist}
>>> b
{'one': '0', 'two': '0', 'three': '0', 'four': '0', 'five': '0'}

いや、これだったらfromkeysメソッド使ったほうがいいか。私のわからないところでdict型で内包表記するメリットがあるかも知れないので、「dictで内包表記は可能」ということだけ覚えておこうと思います。

Pythonのdictのまとめ

まとめ

  • Pythonのdict型は辞書型と呼ばれ、キーと値がペアになったオブジェクトの型
  • dict型に対しては、要素の読み込み、追加、更新、削除、コピー、ソートなどが可能
  • json.dumpでdict型をjson形式に変換できる