Pythonのコード改修をしていてdict.get('key3').get(key3f)
のような記述があり、「なんでや!dict['key3']['key3f']
でええやろ!.get
の4文字余分やろ!」と思ったので、なぜこういったコーディングになるのかの理由を調べた。
結論
keyで指定するとKeyError
になりエラーハンドリングしていない場合は途中終了するが、get()
の場合はNone
が返ってくるため、場合によっては途中終了しない。
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
(公式ドキュメントより)
検証
以下、検証。
環境
$ python --version
Python 3.12.0
key指定する場合
以下のようなdictが入ったlistをの要素をprintするだけのコードを実行してみる。
places = [
{
'name': '東京',
'attraction': '東京スカイツリー'
},
{
'name': '神奈川',
'attraction': '横浜中華街'
},
{
'name': '栃木'
}
]
for place in places:
print(place['name'])
print(place['attraction'])
実行結果
栃木にはattractionの要素がないためKeyError
となる。
$ print_dict_by_key.py
東京
東京スカイツリー
神奈川
横浜中華街
栃木
Traceback (most recent call last):
File "file_to_path\print_dict_by_key.py", line 17, in <module>
print(place['attraction'])
~~~~~^^^^^^^^^^^^^^
KeyError: 'attraction'
get()メソッドを使う場合
以下のようにprint部分を変更
places = [
{
'name': '東京',
'attraction': '東京スカイツリー'
},
{
'name': '神奈川',
'attraction': '横浜中華街'
},
{
'name': '栃木'
}
]
for place in places:
print(place.get('name'))
print(place.get('attraction'))
実行結果
None
が出力され、エラーにならない。
$ python rint_dict_by_get.py
東京
東京スカイツリー
神奈川
横浜中華街
栃木
None
検証からわかること
dict内に指定したkeyが存在することが保証されている場合は(コードの見やすさ的にも)key指定の方が良いが、そうでない場合はget()
を使った方が安全と言える。
例えば、外部サービス等からdictが渡ってきて、それをログにひたすらprintするシステムがあり、渡ってくるdictの形式が状況によって変動する、もしくは渡ってくるdictの全容がそもそもわからない、という場合など。
ハンドリングのしやすさ
get()
の場合はNone
が返ってくるので、以下のような方法を使えばわざわざtry-except
しなくて済む。
このNone
は<class 'str'>
ではなく、<class 'NoneType'>
なので注意。
①if分岐
None
が返ってくるとなると以下のifを思いつくだろう。
places = [
{
'name': '東京',
'attraction': '東京スカイツリー'
},
{
'name': '神奈川',
'attraction': '横浜中華街'
},
{
'name': '栃木'
}
]
for place in places:
print('----')
print('Q:' + place.get('name') + 'の魅力は?')
if place.get('attraction') is None:
print('- ないんだな、それが')
else:
print('- ' + place.get('attraction'))
実行結果
$ python print_attraction.py
----
Q:東京の魅力は?
- 東京スカイツリー
----
Q:神奈川の魅力は?
- 横浜中華街
----
Q:栃木の魅力は?
- ないんだな、それが
②get()メソッドのdefaultを使う
get()メソッドは第二引数にデフォルト値を渡すことができ、None
が返ってきた時にデフォルト値を出力するようにすることも可能。
上記コードのループ部分を以下のように書き換えても同様の処理になる。
for place in places:
print('----')
print('Q:' + place.get('name') + 'の魅力は?')
print('- ' + place.get('attraction', 'ないんだな、それが'))
コードがスッキリするためこっちの方が好み。
まとめ
dictのkey状態がよくわからなかったらget()
の方が安全だが、<class 'NoneType'>
なところは注意が必要そう。