🐍

Pythonのセイウチ演算子を1つのif文内で複数使うときの注意点

2024/07/04に公開

やりたいこと

  • dict型の変数 dict から キー a , b の値を変数に格納する
  • a , b 両方のキーが存在する場合のみ処理をする
    これをセイウチ演算子を用いて実装したい。

結論

セイウチ演算子をandでつなげる場合はそれぞれ() で囲う必要がある

検証

実装1:これはエラーになる。

dict = {"a": 1, "b": 2}

if a := dict.get("a") and b := dict.get("b"):
    print(f"a = {a}")
    print(f"b = {b}")

#$ python3 walrus.py 
#  File "walrus.py", line 25
#    if a := dict.get("a") and b := dict.get("b"):
#                                ^
#SyntaxError: invalid syntax

実装2:様子がおかしい

dict = {"a": 1, "b": 2}

if a := dict.get("a") and (b := dict.get("b")):
    print(f"a = {a}")
    print(f"b = {b}")

#$ python3 walrus.py 
#a = 2 #ここは1が期待
#b = 2

これは

a := (dict.get("a") and (b := dict.get("b"))):

と等価になるっぽい。
:= の右側を全部処理してから a に代入している

実装3:解決

dict = {"a": 1, "b": 2}

if (a := dict.get("a")) and (b := dict.get("b")):
    print(f"a = {a}")
    print(f"b = {b}")

#$ python3 walrus.py 
#a = 1
#b = 2

余談:pythonのand (or) の特徴

and, or は真偽値ではなく、値自体を返す。
そのため、実装2の場合に、a には True ではなく 2 が代入される。
https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not

Discussion