ブール値以外をif文で判定した時の挙動

はじめに

今回はPythonのif文の動きについて少し掘り下げてみよう。

以下のコードはTrueFalseどちらを出力するだろうか。

1
2
3
4
if 0:
print ('True')
else:
print ('False')

また、以下のコードだとどうだろうか。

1
2
3
4
if 1:
print ('True')
else:
print ('False')

上記の例はプログラミングに慣れた人だと知っているかもしれない。

では、

1
if 2:
1
if ['A']:
1
if []:
1
if 'apple':

だとどうなるだろうか。エラーは発生するだろうか。

結論から言うと、エラーは発生しない。

何らかの形で、オブジェクトは真理値として判定できるからだ。

真理値判定

どのようなオブジェクトでも真理値として判定でき、ifやwhileの条件あるいは以下のブール演算の被演算子として使えます。オブジェクトは、デフォルトでは真と判定されます。ただしそのクラスが __bool__()メソッドを定義していて、それがFalseを返す場合、または__len__()メソッドを定義していて、それが0を返す場合は偽と判定されます。
(https://docs.python.org/ja/3/library/stdtypes.html#truth)

つまり、はじめにで示した例だと、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> bool(0)
False

>>> bool(1)
True

>>> bool(2)
True

>>> bool(['A'])
True

>>> bool([])
False

>>> bool('apple')
True

が、__bool__()の値であり、かつ問題の答え(標準出力される文字列)となる。

(数値型のbool()は0のみがFalseとなる)

ここでふと疑問が浮かぶ。

__bool__()__len__()はどちらが優先度が高いのだろう。

クラスを作って、実験してみよう。

__bool__()__len__()

__bool__()がTrue、__len__()が0の場合

だとどうなるのだろうか。

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass:
def __init__(self):
pass
def __bool__(self):
return True
def __len__(self):
return 0
m = MyClass()
if m:
print ('True')
else:
print ('False')

__bool__()が優先されている。

1
True

__bool__()がFalse、__len__()が非0の場合

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass:
def __init__(self):
pass
def __bool__(self):
return True
def __len__(self):
return 0
m = MyClass()
if m:
print ('True')
else:
print ('False')
1
False

こちらも__bool__()が優先されている。

つまり、__bool__()の優先順位が高いと言える。

実は、答えはドキュメントからも読み取れる。

object.bool(self)真理値テストや組み込み演算bool()を実装するために呼び出されます。このメソッドが定義されていないとき、__len__()が定義されていれば呼び出され、その結果が非0であれば真とみなされます。

(https://docs.python.org/ja/3/reference/datamodel.html#object.__bool__)

__bool__()__len__()も定義されていない場合

ドキュメントにあったように、オブジェクトはデフォルトではTrueとなる。

1
2
3
4
5
6
7
8
class MyClass:
def __init__(self):
pass
m = MyClass()
if m:
print ('True')
else:
print ('False')
1
True

まとめ

  1. __bool__()を評価する。
  2. __bool__()が定義されていない場合、__len__()を評価する。
  3. __len__()が定義されていない場合、Trueを返却する。

記事情報

  • 投稿日:2020年3月15日
  • 最終更新日:2020年3月15日