home changes contents help options

115:ハッシュ内にキーが存在するか調べる

Ruby のハッシュの役割をする Python の型は 辞書 です。辞書にあるキーが存在することを調べるには in 演算子を、しないことを調べるには not in 演算子を用います。

>>> d = {}
>>> d = {'a': None}
>>> 'a' in d
True
>>> 'b' in d
False
>>>
>>> 'a' not in d
False
>>> 'b' not in d
True

別の方法としては、アクセスしてみて KeyError? 例外が送出されないかどうか調べる、というのもあるにはあります。しかし、 in 演算子の方が勝ります。

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

キーが無く、値が得られなかったときにも別の値を代わりに使って処理続行したい、という場合があります。このとき、 in 演算子で確認して条件分岐したり KeyError? を捕捉して再処理、とする必要はありません。 get メソッドを用いるとうまくできます。

>>> x = d.get('b', 0)
>>> x
0
>>>
>>> # get メソッドのほうが簡単、必要は無い
>>> if 'b' in d:
...   y = d['b']
... else:
...   y = 0
...
>>> y
0
>>>
>>> try:
...   z = d['b']
... except KeyError:
...   z = 0
...
>>> z
0

キーがあるときはその値を返し、無いときにはデフォルト値をセットしつつ返す、という処理が役に立つことがあります。たとえば入れ子のコレクションを作成するときです。setdefault メソッドはまさにこのために用意されたものです。次のコードはリストが含まれる辞書を作成する例です。キーがあるときはそのまま、無いときは新たに空のリストを用意するということができます。

>>> d = {}
>>> d.setdefault('a', []).append(1)
>>> d.setdefault('a', []).append(2)
>>> d.setdefault('a', []).append(3)
>>> d.setdefault('b', []).append(4)
>>> d.setdefault('b', []).append(5)
>>> d
{'a': [1, 2, 3], 'b': [4, 5]}

これだとなんの役に立つのかわかりにくいですが、次のようにすると setdefault のメリットが見えてきます。内側の for 文の内容は 1 行でありながら、キーの有無による場合わけ、空のリストの用意、リストへの値の append という複雑な処理をこなしています。

>>> d = {}
>>> keys = ['a', 'b']
>>> values = ((1, 2, 3), (4,5))
>>> for key, values2 in zip(keys, values):
...   for value in values2:
...     d.setdefault(key, []).append(value)
...
>>> d
{'a': [1, 2, 3], 'b': [4, 5]}