質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

解決済

python 変数に辞書の値を入れたいが辞書に値がない時エラーになる

ngmg
ngmg

総合スコア67

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

2回答

1グッド

0クリップ

185閲覧

投稿2022/11/17 03:32

実現したいこと

辞書にあるアイテムを変数に入れたいのですが、何らかの理由で辞書の情報が欠けてしまっている場合があります。
ソースコードでは 'utao' のweightが欠けていますがageやheightが欠けている場合もあります。
辞書にアイテムが存在するということを前提に変数に入れているので欠けていた場合エラーが出てしまいます。

こういうイレギュラーを防ぐために辞書のチェックを行い、欠けていた場合は暫定の値を入れるみたいなことをしたいのですがどうすればよいでしょうか?

エラー

__sent_weight = list[name]['weight'] KeyError: 'weight'

該当のソースコード

list = { 'jone': {'age': 20, 'height': 180, 'weight': 75}, 'kaori': {'age': 18, 'height': 160, 'weight': 43}, 'utao': {'age': 16, 'height': 175}, } async def get_items(name, list): if list.get(name, None) is not None: _sent_age = list[name]['age'] _sent_height = list[name]['height'] _sent_weight = list[name]['weight']
kensoon👍を押しています

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

meg_

2022/11/17 12:59

エラーと直接は関係ありませんが、変数名に「list」を使うのは止めましょう。

回答2

0

get(key, default) を使いましょう。

python

1 _sent_weight = list[name].get('weight', -1)

投稿2022/11/18 06:45

int32_t

総合スコア17087

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

0

ベストアンサー

こんにちは。初学者の回答になりますので、話半分くらいで聞いていただけると幸いです。実際、asyncのところの表記は今ひとつ理解ができていませんので、「欠けていた場合は暫定の値を入れる」というところに絞って回答させていただきます。

さて本題ですが、コードと質問の方を読ませていただく限り、defaultdictで解決できると思われます。defaultdictはコンテナデータ型の一つで、生成時に関数を引数として与えることで、その関数が自動的に初期化を行ってくれるようになります。サンプルコードとしてはこんな感じ。

python

1from collections import defaultdict 2 3utao_profile = defaultdict(int) 4utao_profile['age'] = 16 5utao_profile['height'] = 175 6 7print(utao_profile['age']) 8print(utao_profile['height']) 9print(utao_profile['weight'])
16 175 0

ここではintを関数として与えています。intは引数を取らない時に0を返しますので、存在しない'weight'というキーを読み込んだときにもエラーを吐かず、ゼロを出力してくれます。

もちろんこの関数は自作しても良いです。値が存在しないということで、Noneを格納して欲しければ、Noneを返す関数を自作して与えてあげればOK。

python

1from collections import defaultdict 2 3def NoneMaker(): 4 return None 5 6utao_profile = defaultdict(NoneMaker) 7utao_profile['age'] = 16 8utao_profile['height'] = 175 9 10print(utao_profile['age']) 11print(utao_profile['height']) 12print(utao_profile['weight'])
16 175 None

ただ、この程度の働きであれば、関数を定義するまでもなく無名関数を使ってあげればよいでしょう。lambda: 値とすることで、任意の値を返す名無しの関数が作れます。

ということで、書かれているものと(おおむね)同じ働きをするコードは以下のようになります。

python

1from collections import defaultdict 2 3 4jone_profile = defaultdict(lambda: None) 5jone_profile['age'] = 20 6jone_profile['height'] = 180 7jone_profile['weight'] = 75 8 9kaori_profile = defaultdict(lambda: None) 10kaori_profile['age'] = 18 11kaori_profile['height'] = 160 12kaori_profile['weight'] = 43 13 14utao_profile = defaultdict(lambda: None) 15utao_profile['age'] = 16 16utao_profile['height'] = 175 17 18profiles = { 19 'jone': jone_profile, 20 'kaori': kaori_profile, 21 'utao': utao_profile, 22} 23 24print(profiles['jone']['age']) 25print(profiles['utao']['weight'])
20 None

ただ、このコードにも少し問題がありまして、それはどんなキーでアクセスしてもエラーを吐かずNoneが返ってくることです。上の例だと誕生日だとかでアクセスをかけてもNoneが返ってきてしまいます。

python

1print(profiles['jone']['birthday'])
None

想定しない値へのアクセスは防ぎつつ、デフォルトの値を設定したいのであれば、NamedTupleとOptionalの併用も視野に入るでしょう。NamedTupleは.属性名でアクセスできるコンテナの一種で、Optionalと併用することで、「基本はNoneで、値が入力された場合はそちらを採用」といった形で利用することが可能です。この方法であれば存在していない属性へのアクセスが防げて、かつ決まったデータ型を格納することもできるようになります。

python

1from typing import NamedTuple, Optional 2 3class Profile(NamedTuple): 4 name: str 5 age: Optional[int] = None 6 height: Optional[int] = None 7 weight: Optional[int] = None 8 9jone_profile = Profile(name='jone', age=20, height=180, weight=75) 10utao_profile = Profile(name='utao', age=16, height =175) 11 12print(jone_profile.weight) 13print(utao_profile.weight)
75 None

必ず与えられる属性は、"属性名: データ型"。与えられないかもしれない属性は"属性: Optional[想定されるデータ型] = デフォルト値"という使い方です。こいつなら、

python

1print(utao_profile.birthday)

というアクセスがあっても、

AttributeError: 'Profile' object has no attribute 'birthday'

「そんなもん設定されてないよ」と返してくれます。

以上、なにかの参考になれば幸いです。

(追記)
だーっと書いて見直してから気づいたのですが、「辞書側には干渉できない」という可能性が頭から抜けてました。その場合は力技にはなりますが、for文+valuesで中身の辞書を取り出してから、setdefaultメソッドで片っ端から値を代入するのが手っ取り早いかもしれません。setdefaultは辞書に備え付けられたメソッドの一つで、setdefault(key, value)とすることで、keyが存在しない場合のみ、valueが新たな値として追加されるという働きをします。

python

1profiles = { 2 'jone': {'age': 20, 'height': 180, 'weight': 75}, 3 'kaori': {'age': 18, 'height': 160, 'weight': 43}, 4 'utao': {'age': 16, 'height': 175}, 5} 6 7for profile_dict in profiles.values(): 8 profile_dict.setdefault('age', None) 9 profile_dict.setdefault('height', None) 10 profile_dict.setdefault('weight', None) 11 12print(profiles)
{'jone': {'age': 20, 'height': 180, 'weight': 75}, 'kaori': {'age': 18, 'height': 160, 'weight': 43}, 'utao': {'age': 16, 'height': 175, 'weight': None}}

投稿2022/11/17 16:36

編集2022/11/17 17:09
kensoon

総合スコア48

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

ngmg

2022/11/18 03:39

すごいです!とても丁寧に解説頂きありがとうございます! 自分の知らない方法を聞けて感激です。 こちらの方法でやってみたいと思います。 ありがとうございました!

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。