0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで辞書に複数のキーが含まれるか確認したい

Posted at

ループの中で、辞書 medium_infonamesize の2つの必須キーがなければ処理をスキップ、という処理を書きたい。
一つのキーの存在確認なら知ってたが、複数のキーが全て存在することの確認方法がわからなかったので調べてみた。

結論

if not {"name", "size"}.issubset(medium_info):
    continue

経緯

最初に書いたコードは以下の通り。

最初に書いたコード(間違ってないけどダサい)
if ("name" not in medium_info
        or "size" not in medium_info):
    continue

まあ直球でわかりやすいっちゃわかりやすいけど長い。
それまでのインデントもあって79文字に収めるには改行が必要で、改行するためにカッコもつけたりといろいろめんどくさい。書くのも読むのも。

なにかもっといい書き方はないものかとググっていると、素敵な記事を発見。
こんなんでできるっぽい。

記事を参考に修正(正しいし簡潔だけど・・・)
if not (medium_info.keys() >= {"name", "size"}):
    continue

うん。ぐっと短く簡潔になった。
けど・・・Pythonニワカの俺的に、ぱっと見て何してるのか全くわからん。
まず {...} ってなに?辞書っぽいけど値ない?
あー、setの定義か。全然覚えてなかったけどそういや試験出たわ。
そんな出発点から調査開始。

ふむふむ。集合演算なのね。
集合Bが集合Aの部分集合、つまり集合Bの全要素が集合Aに含まれる場合に A >= B が真になると。
というあたりを理解しないままに書いたコードがこちら。

記事を参考に最初に書いたコード(誤り)
if medium_info.keys() < {"name", "size"}:
    continue

いやわかるっしょ?こうしたくなる気持ち。
not A >= BA < B でしょ。普通。
でも集合演算的には {"name", "size"} に含まれないキーが medium_info に入っていれば試合終了。残念無念。

とにかく、 not (A >= B) != A < B とか集合演算のルールが許しても俺の気持ち的に許せない。
忘れた頃に「あれ?変なことしてる!」と発見して修正のつもりでバグらせて悩んで戻す、を何回かやりそう。
もう少し気持ちに届く表現をしたい。
ということで同じ意味をメソッドで。

演算子をメソッドに変更(わかりやすい)
if not {"name", "size"}.issubset(medium_info.keys()):
    continue

うん。わかりやすい。
「部分集合ではない」と「スーパーセットである」が同じ意味じゃないのはさすがにわかるし、名前って大事だね。
さらに、演算子バージョンでは両辺が集合である必要があったが、メソッドの引数では制限が緩和されてもう少し柔軟担っているので、.key() も省略可能。

演算子をメソッドに変更(わかりやすくて簡潔)
if not {"name", "size"}.issubset(medium_info):
    continue

ちょっとわかりにくくなってる気もするが、"name" in medium_info といった書き方には慣れてるので medium_info そのものでキーの集合を参照することに違和感は感じない。

その他、元記事にない方法も考えてみた。

引き算
if {"name", "size"} - medium_info.keys() != set():
    continue

namesizeの両方がmedium_infoに入っていれば、空になる。
namesizeのどちらかmedium_infoに入っていないものがあれば空にならない。
言語的なことを言えば != set()がなくても問題ない。
簡潔といえば簡潔・・・だけどやっぱりわかりやすいとは思えんな。
演算子をメソッドに置き換えたところでやっぱり迂遠な感じは否めない。

引き算(メソッド版)
if {"name", "size"}.difference(medium_info):
    continue

息するように集合演算するタイプの人ならわかりやすいかもしれんが俺は無理。
{"name", "size"}medium_infoに差 (difference) があるってことは、つまり {"name", "size"} != medium_info ってだけじゃね?とすら思えるし。

ということで、issubset() 版をファイナルアンサーとしておく。

まあでも結局のところ、どのくらいPythonとか集合演算に慣れているかで、どれが一番わかりやすいと感じるかは変わってくるんだろうね。

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?