ループの中で、辞書 medium_info に name と size の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 >= B は A < 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
nameとsizeの両方がmedium_infoに入っていれば、空になる。
nameとsizeのどちらかmedium_infoに入っていないものがあれば空にならない。
言語的なことを言えば != set()がなくても問題ない。
簡潔といえば簡潔・・・だけどやっぱりわかりやすいとは思えんな。
演算子をメソッドに置き換えたところでやっぱり迂遠な感じは否めない。
if {"name", "size"}.difference(medium_info):
continue
息するように集合演算するタイプの人ならわかりやすいかもしれんが俺は無理。
{"name", "size"}とmedium_infoに差 (difference) があるってことは、つまり {"name", "size"} != medium_info ってだけじゃね?とすら思えるし。
ということで、issubset() 版をファイナルアンサーとしておく。
まあでも結局のところ、どのくらいPythonとか集合演算に慣れているかで、どれが一番わかりやすいと感じるかは変わってくるんだろうね。