Pythonの or は「または」ではない

単にTrueかFalseを返す演算子ではない

Pythonの or は「または」の意味だと說明されることがあります。

x = 10

# x は 10 または 20
if x == 10 or x == 20:
    print("xは10か20です")

# 実行結果:xは10か20です

しかしこのコードの実行結果を見ると、 or は単なる「または」ではないことがわかります。

a = False
b = 123
print(a or b)

# 実行結果: 123
# Trueではない

じゃあ何なのか

公式ドキュメントには下記の說明があります。

式 x or y は、まず x を評価します; x が真なら x の値を返します; それ以外の場合には、 y を評価した結果値を返します。

docs.python.org – 6. 式 (expression)

オブジェクトを返す演算子

or は両端の値のうち、 最初にTrueと評価される値 を返します。

true_value_1 = 100
true_value_2 = 200

print(true_value_1 or true_value_2)

# 実行結果: 100

# true_value_1 or true_value_2 の中で、
# true_value_1 が最初にTrueと評価される値である → 100

両方がFalseと評されるなら、右側の値を返します。

false_value_1 = False
false_value_2 = 0
print(false_value_1 or false_value_2)

# 実行結果: 0

# false_value_1 or false_value_2 の中で、Trueと評価される値はなかった。
# false_value_2 が右側の値である → 0

※より正確には、返されるのは「値や式の評価結果」です。

つまりどういうことか

or が返すのは or の両端の値のどちらかです。どちらが返されるかは、その両端の値がTrueとFalseどちらに評価されるかによって決まります。

Pythonの or はJavaなどの言語と異なり、真偽値(True, False)しか受け取れない演算子ではありません。あらゆる値をオペランドに(つまりorの両側に)持つことができます。

つまり先に登場したif文は厳密に言うと下記の流れをたどっているということです。

x = 10
if x == 10 or x == 20: 
# ↓ 
# if True or False: # or の両端の式がまず計算される
# ↓
# if True: # orの左側の値がTrue。よってorは左側の値のTrueを返す
    print("xは10か20です")

# 実行結果: xは10か20です

両方ともFalseとなる場合は下記のとおりです。

x = 100000
if x == 10 or x == 20: 
# ↓ 
# if False or False: # or の両端の式がまず計算される
# ↓
# if False: # orの両端がFalse。よってorは右側のFalseを返す
    print("xは10か20です")

# 実行結果: (何も出力されない)

どう役立つのか

関数の引数のデフォルト値

関数の引数に偽と評価される値 (None 0 "" など)が渡された場合のデフォルト値を設定できます。

def greet(name=None):
    name = name or "Guest"
    print(f"Hello, {name}!")

greet()  # 出力: Hello, Guest!
greet("Alice")  # 出力: Hello, Alice!

PHPの言語でサポートされているNull合体演算子の代わりのように使えるということです。

hoge = None

# if hoge is None:
#    hoge = "Hello World!"
# ↑↓同じ実行結果
hoge = hoge or "Hello World!"

print(hoge)

# PHPのNull合体演算子に近い
# $hoge = $hoge ?? "Hello World!"

例えばどんなところで役立っているのか

Django(PythonでWebアプリケーションを作るときに使われる、代表的なフレームワーク)でFormのオブジェクトを生成する際は下記のように書くのがお約束です。

form = Form(request.POST or None)

request.POST or None は、 request.POST に値が入っていれば下記のように評価され、

# request.POST に値が入っている場合(Trueと評価される場合)
form = Form(request.POST)

request.POST がFalseと評価される(値が無いなど)場合は下記のように評価されるということです。

# request.POST がFalseと評価される場合(値が入っていないなど)
form = Form(None) # Form() と同義

参考:Logic behind Form(request.POST or None) – StackOverflow