Help us understand the problem. What is going on with this article?

Python の or と and 演算子の罠

More than 3 years have passed since last update.

普通、プログラム言語ではorand (または||&&などの類似表現) は (2項の) 論理演算を意味します。
つまりorandが返す値は bool 値 (True/False) です。
C系の言語では True/False が 1/0 で代用されたりもしますが、とにかく論理演算 or と and は論理値に相当する値を返します。
しかし、Python では、orandは論理値を返すとは限りません。
Pythonにおいて、式x and yは、次と等価です:

if not bool(x):  # xの論理値がFalseなら
    return x  # yを見ることなく、しかもFalseではなくxそのものをリターン
else:  # xの論理値がTrueなら
    return y  # bool(y) ではなく、yそのものをリターン

同様に、式x or yは次と等価です:

if bool(x):  # xの論理値がTrueなら
    return x  # yを見ることなく、しかもTrueではなくxそのものをリターン
else:  # xの論理値がFalseなら
    return y  # bool(y) ではなく、yそのものをリターン

Pythonでは、長さ0の文字列の論理値がFalse、長さ1以上の文字列の論理値がTrueであることに気をつけると、次のようにまとめることができます:

'123' or '456'  -> '123'  # bool('123') がTrueなので、 左辺値'123'をリターン
'123' or ''     -> '123'  # bool('123') がTrueなので、 左辺値'123'をリターン
''    or '456'  -> '456'  # bool('')    がFalseなので、右辺値'456'をリターン
''    or ''     -> ''     # bool('')    がFalseなので、右辺値''   をリターン
'123' and '456' -> '456'  # bool('123') がTrueなので、 右辺値'456'をリターン
'123' and ''    -> ''     # bool('123') がTrueなので、 右辺値''   をリターン
''    and '456' -> ''     # bool('')    がFalseなので、左辺値''   をリターン
''    and ''    -> ''     # bool('')    がFalseなので、左辺値''   をリターン

上の例では、orandの結果であるにも関わらず、True/Falseは一切返ってきません
もしもPythonで2項論理演算子 (orとand) から返ってくる値が常に論理値True/Falseであることを保証したい場合は、bool(x) or bool(y)またはbool(x) and bool(y)とする必要があります (bool(x or y), bool(x and y) でも良いですが)。
普通、xyとして論理値True/False以外の値を渡すことはないですが、自動的にbool(x)が評価されるため、たまに忘れることがあります。
なんでこんなことになっているのかというと、よく言われているのは、Noneの扱いが便利になるからだそうです。
PythonではNoneの論理値はFalseです (bool(None) -> False) ので、次のコード

# x には None が格納されているのかどうかわからない
if x is None:
    x = '456'
# x = '456' if x is None とも書けるが個人的に好きじゃない

は、x = x or '456'で代用できます
ただし、等価ではありませんxに 空文字列''や 空リスト[]が格納されていた時の振る舞いが異なります。
x''[]が格納されていた場合、x is Nonebool(x)Falseです。よって、 is Noneを用いたコードの場合xは再代入されませんが、
x or '456'を用いたコードの場合xには'456'が再代入されます。

待て、 if x or y: はどうなる?

もしもorが論理値を返さないとするならば、ifで今までx or yを使っていたのは偶然うまくいっていたのか?
いえ、それは偶然ではなく必然的にうまくいっていました。
Pythonでは、ifの条件式は勝手に真理値が判別されます。つまり、if bool(x or y): と同じことが勝手におこなわれています。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした