【ITニュース解説】Understanding truthiness, falsiness, and the quiet meaning of emptiness in Python
2025年09月12日に「Dev.to」が公開したITニュース「Understanding truthiness, falsiness, and the quiet meaning of emptiness in Python」について初心者にもわかりやすく解説しています。
ITニュース概要
Pythonオブジェクトの真偽値は、`__bool__`メソッドで定義され、なければ`__len__`の戻り値、またはデフォルトで決まる。カスタムクラスでこれらを実装し、オブジェクトの論理的な意味を明確にすることで、コードの意図を伝わりやすく設計できる。ただし、定義は直感的にすることが重要だ。
ITニュース解説
Pythonでは、プログラムの中で「もし〜ならば、これを実行する」といった条件分岐をよく使う。この「もし〜ならば」の条件が「真(True)」か「偽(False)」かを判断する際に、Pythonのオブジェクトがどのように振る舞うか、という考え方が「真偽性(truthiness)」と「偽偽性(falsiness)」だ。Pythonは、単に「True」か「False」という二択だけでなく、あるオブジェクトが論理的な文脈において「自分自身について何を語っているか」と問いかけている。
例えば、if文の中でif some_object:というコードがあった場合、Pythonはこのsome_objectが真として扱われるべきか、偽として扱われるべきかを判断する。この判断のプロセスは次の順序で行われる。まず、Pythonはそのオブジェクトに__bool__(アンダースコアが2つずつ付いたboolメソッド)が定義されているかを確認する。もし__bool__メソッドが定義されていれば、Pythonはそのメソッドを呼び出し、その戻り値に基づいて真偽を判断する。
もし__bool__メソッドが定義されていなかった場合、Pythonは次に__len__(アンダースコアが2つずつ付いたlenメソッド)が定義されているかを確認する。__len__メソッドは、リストや文字列のように、オブジェクトが持つ要素の「長さ」や「数」を返すものだ。もし__len__メソッドが定義されており、その戻り値が0(ゼロ)であれば、そのオブジェクトは「偽」として扱われる。それ以外の、0以外の長さを持つ場合は「真」として扱われる。これは、空のリスト[]や空の文字列""が偽として扱われ、要素を持つリストや文字列が真として扱われる理由だ。
そして、もし__bool__も__len__もどちらも定義されていない場合、Pythonはそのオブジェクトをデフォルトで「真」として扱う。つまり、特に何も定義されていない限り、どんなオブジェクトもif文の条件で「真」と判断されるということだ。この仕組みにより、開発者は自分で作成するクラス(オブジェクトのひな形)に対しても、そのオブジェクトがどのような場合に真であり、どのような場合に偽であるかを自由に定義できるようになる。
具体的な例で考えてみよう。例えば、テキストを保持する簡単なScroll(巻物)クラスを作成する。
1class Scroll: 2 def __init__(self, text): 3 self.text = text
このScrollクラスには__bool__も__len__も定義されていない。ここで次のようなコードを実行してみる。
1s = Scroll("Do not seek the truth, only cease to cherish opinions.") 2if s: 3 print("The scroll speaks.") 4else: 5 print("The scroll is silent.")
この場合、結果は常に"The scroll speaks."と表示される。なぜなら、Scrollクラスには__bool__も__len__も定義されていないため、Pythonはデフォルトのルールに従い、sオブジェクトを真とみなすからだ。
しかし、__bool__メソッドを定義することで、この振る舞いを変更できる。
1class Scroll: 2 def __init__(self, text): 3 self.text = text 4 5 def __bool__(self): 6 return bool(self.text.strip())
このように__bool__メソッドを追加すると、Scrollオブジェクトの真偽性が変わる。ここでは、self.text.strip()が返す文字列をbool()関数で評価している。strip()は文字列の前後にある空白を取り除くメソッドなので、例えば" "(空白のみの文字列)は空の文字列""になる。空の文字列はPythonでは偽として扱われるため、bool("")はFalseを返す。一方、"Peace"のような意味のある文字列は真として扱われるため、bool("Peace")はTrueを返す。
これにより、Scroll(" ")というオブジェクトは偽として振る舞い、Scroll("Peace")というオブジェクトは真として振る舞うようになる。私たちは__bool__メソッドを使って、オブジェクトが「そこに何か意味のある情報があるか」を表現するように教えたわけだ。
次に、__bool__が定義されていない場合にPythonが__len__を参照する例を見てみよう。例えば、WisdomBasket(知恵の籠)というクラスを考える。この籠は、複数の「知恵の言葉」をsayingsというリストに格納する。
1class WisdomBasket: 2 def __init__(self): 3 self.sayings = [] 4 5 def __len__(self): 6 return len(self.sayings)
このWisdomBasketクラスでは__bool__は定義されていないが、__len__が定義されている。__len__メソッドは、sayingsリストの長さを返すようにしている。したがって、sayingsリストが空であれば0を返し、要素があれば0以外の値を返す。
ここで次のようにコードを実行してみる。
1basket = WisdomBasket() 2if basket: 3 print("There is wisdom.") 4else: 5 print("The basket is empty.")
初期状態のbasketオブジェクトにはsayingsリストが空のため、basket.__len__()は0を返す。そのため、if basket:の条件は偽と判断され、"The basket is empty."と表示される。もしbasket.sayings.append("Never give up.")のように要素を追加すれば、__len__は1を返し、if basket:は真と判断されるようになる。このように、オブジェクトがコレクション(複数の要素を持つもの)を表しており、その内容の有無が真偽性と結びつく場合に__len__は非常に便利だ。
では、なぜこの真偽性の設計が重要なのか。それは、実際のプログラミングにおいて「真偽性」がしばしばそのオブジェクトの「意味」そのものを表すからだ。例えば、WebアプリケーションでHTTPリクエストの応答を受け取るresponseオブジェクトがあったとして、if response:というコードを書いた場合、このresponseが真であることは何を意味するべきだろうか。HTTPリクエストが成功したことだろうか?応答の本文に有用なデータが含まれていたことだろうか?それとも、ステータスコードが200 OKだったことだろうか?
このように、__bool__メソッドを定義することで、あなたはresponseオブジェクトがブールコンテキストにおいて何を伝えるべきかを明確に決定できる。APIを設計したり、内部ライブラリを作成したり、あるいは独自のクラスを定義したりする際に、真偽性を明確に定義しておくことは、余計な定型文(例えばif response.is_ok():やif response.has_data():のようなもの)を減らし、コードの意図をより明確に、一目でわかるようにする効果がある。
しかし、この真偽性の設計には注意点もある。真偽性は常に「曖昧さがないこと」と「直感的であること」が重要だ。もしあなたのオブジェクトが設定、リクエスト、またはリソースなどを表す場合、「真」であるとは具体的に何を意味するのかをよく考える必要がある。例えば、if config:というコードがあったとして、これが「設定ファイルが存在する」という意味なのか、「設定が有効である」という意味なのか、「特定の設定項目がオンになっている」という意味なのかが不明瞭だと、コードの意図が伝わりにくくなり、後で読み返す人や別の開発者が混乱する原因になる。
このような曖昧さを避けるためには、真偽性の意味をしっかりとドキュメントに記述するか、あるいは意味が不明瞭になりそうであれば、そもそも真偽性を使うことを避け、より明示的なメソッド(例えばconfig.is_valid()など)を使用する方が良い場合もある。
結局のところ、Pythonにおける真偽性は固定されたものではない。それは、あなたがオブジェクトをどのように設計するかによって生み出される影のようなものだ。オブジェクトがどのような光を反射するのか、あるいは光がないことを示すのか、それを選択するのはプログラマであるあなた自身なのだ。この深い理解は、より読みやすく、より意図が明確なコードを書くための強力なツールとなるだろう。