1
0

辞書(dict型)でkey指定で値を取得するのとget()メソッドを使うのは何が違うのか【Python】

Last updated at Posted at 2023-10-06

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するだけのコードを実行してみる。

print_dict_by_key.py
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部分を変更

print_dict_by_get.py
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を思いつくだろう。

print_attraction.py
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'>なところは注意が必要そう。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0