1
1

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の真偽値評価で知っておくべき6つの落とし穴

Last updated at Posted at 2024-11-09

こんにちは、とまだです。

Python アドベントカレンダー 2024 のうち、1 日目の記事をお届けします!

こんにちは、とまだです。

突然ですが、以下のコードの実行結果が分かりますか?

x = range(0)
if x:
    print("これは実行される?")

x の中身は空の range オブジェクトですが、あくまでオブジェクトなのでちょっと難しいと思うかもしれません。

ただ、答えは「空の range()オブジェクトだから実行されない」です。

$ python main.py
$

Python では range(0) は空のシーケンスを表すため、if 文の条件式は False になります。

でも、こんなコードはどうでしょう?

y = range(0)
z = range(0)
print(y == z)
print(y is z)

先ほどと同じく、range(0) は空のシーケンスですが、比較演算子によって結果が異なります。

$ python main.py
True
False

== 演算子では True になりますが、is 演算子では False になります。

同じ range(0) なのに、比較演算子によって結果が変わってしまうんですね...。

これは Python の真偽値評価における「落とし穴」の 1 つです。

今回は、私が実際に開発中にハマってしまった(もしくは他の人がハマっているのを見かけた)真偽値評価の落とし穴を 7 つ紹介します。

この記事で学べること

  • Python の真偽値評価の基本的な仕組み
  • よくある落とし穴とその対処法
  • バグを未然に防ぐための対策

真偽値はプログラミングの基本

真偽値評価は、条件分岐やループなど、プログラミングの基本中の基本です。

しかし、Python の真偽値評価には他の言語とは異なる独特の仕組みがあり、これが思わぬバグの原因になることがあります。

では、具体的な落とし穴を見ていきましょう!

6 つの落とし穴

落とし穴 1:数値のゼロ判定

数値のゼロ判定で思わぬバグが発生することがあります。

x = 0.0
print(x == 0)    # True
print(bool(x))   # False
print(x is 0)    # False

特に is 演算子を使った比較は要注意です。is は同一性(オブジェクト ID が同じか)を確認するため、数値の比較には適していません。

# 🙅‍♂️ ダメな例:isを使った比較
if x is 0:
    print("実行されない")

# 🙆‍♂️ 良い例:==を使った比較
if x == 0:
    print("実行される")

落とし穴 2:文字列の真偽値評価

空白文字を含む文字列の評価結果は、直感に反することがあります。

print(bool(""))      # False: 空文字
print(bool(" "))     # True: スペース1つ
print(bool("\n"))    # True: 改行のみ

ユーザー入力を処理する際など、この違いは重要です。

# 🙅‍♂️ ダメな例:空白文字のチェックを忘れる
def validate_input(text):
    if text:
        return True
    return False

# 🙆‍♂️ 良い例:strip()で空白文字を除去してからチェック
def validate_input(text):
    if text.strip():
        return True
    return False

落とし穴 3:and/or の戻り値

andor は、最後に評価された値をそのまま返します。これは他の言語にはない Python の特徴です。

print("hello" and [])     # []
print("" or "world")      # "world"
print([] or {} or "last") # "last"

この性質を利用して、デフォルト値を設定することができます。

# 🙆‍♂️ 良い例:デフォルト値の設定
config = user_config or {}
name = user_input.strip() or "Anonymous"

ただし、複雑な条件になると読みにくくなるので注意が必要です。

# 🙅‍♂️ ダメな例:複雑すぎる条件
result = (a and b) or (c and d) or default

# 🙆‍♂️ 良い例:if文で明示的に
if a and b:
    result = b
elif c and d:
    result = d
else:
    result = default

落とし穴 4:None との比較

None との比較は、思わぬバグの原因になりやすいです。

x = None
print(x == False)  # False
print(x is False)  # False
print(bool(x))     # False

NoneFalse とは異なるオブジェクトですが、真偽値評価では False として扱われます。

# 🙅‍♂️ ダメな例:==での比較
if x == None:
    print("実行されない")

# 🙆‍♂️ 良い例:isを使用
if x is None:
    print("実行される")

この場合は逆に is を使うのが Python のイディオムです。

落とし穴 5:演算子の優先順位

andornot の優先順位は、直感とは異なることがあります。

print(True or False and False)  # True
print((True or False) and False)  # False
print(not True or False)  # False
print(not (True or False))  # False

複雑な条件は、括弧を使って明示的に優先順位を示すことをおすすめします。

# 🙅‍♂️ ダメな例:優先順位があいまい
if a and b or c and d:
    print("何が起こる?")

# 🙆‍♂️ 良い例:括弧で明示
if (a and b) or (c and d):
    print("意図が明確")

落とし穴 6:カスタムクラスの真偽値評価

カスタムクラスを作る場合、真偽値評価の挙動を制御できます。

class CustomContainer:
    def __init__(self, items):
        self.items = items

    # __bool__が定義されていない場合は__len__が使用される
    def __len__(self):
        return len(self.items)

empty_container = CustomContainer([])
print(bool(empty_container))  # False

__bool__ メソッドを定義しない場合、__len__ メソッドの戻り値が使用されます。

もう少し正確に言うと、__bool__ が定義されていない場合は、__len__0 の場合に False と評価されます。
(ややこしい)

そのため、以下のように __bool__ メソッドを明示的に定義することをおすすめします。

# 🙆‍♂️ 良い例:明示的に__bool__を定義
class CustomContainer:
    def __init__(self, items):
        self.items = items

    def __bool__(self):
        return bool(self.items)

これにより、クラスのインスタンスの真偽値評価をカスタマイズできます。

まとめ

今回紹介した 7 つの落とし穴を整理すると、以下のようになります。

  1. 数値のゼロ判定は == を使う
  2. 空白文字は空文字とは異なる
  3. and/or は最後に評価された値を返す
  4. None との比較は is を使う
  5. 複雑な条件は括弧を使って明示する
  6. カスタムクラスは __bool__ で挙動を制御できる

これらの落とし穴を知っておくことで、より安全な Python コードを書くことができます。

最後まで読んでいただき、ありがとうございました!

他にもアドベントカレンダー記事を書いています!

他にも、2024 年のアドベントカレンダーに参加しています。

以下の記事でまとめているので、よければ他の記事も読んでいただけると嬉しいです!

1
1
2

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?