Pythonのブール演算について、メモ書きします。
Python2.5 から三項演算子が使えるようになり、私も三項演算子を常用している。Pythonの三項演算子はC言語などとは式の順序が違うため、ちょっと戸惑うが、慣れれば便利に使える。
三項演算子が登場する以前は、ブール演算を三項演算子の代用にしていた。このためフレームワークなどのソースを見ると、ブール演算がよく使われている。
ブール演算が使われているソースを見ると、「あれ、どうだったかな」とその場で調べて納得するのだが、個人的には使わないタイプのコードのためすぐ忘れてしまう。そんな事が何度もあるので、今回、ブール演算をまとめた記事をメモ代りに書いてみます。
真理値テスト
if や while文の条件式に、オブジェクトを指定できる。この時指定するオブジェクトは次のルールで、ブール演算(論理演算)される。
偽(False)として扱われるもの
- None
- False
- 数値型におけるゼロ。例えば 0, 0L, 0.0, 0j 。
- 空のシーケンス型。例えば '', (), [] 。
- 空のマッピング型。例えば {} 。
__nonzero__() または __len__() メソッドが定義されているようなユーザ定義クラスのインスタンスで、それらのメソッドが整数値ゼロまたは bool 値の False を返すとき。 それ以外の値は全て真であると見なされます — 従って、ほとんどの型のオブジェクトは常に真です。
参考: Python 2.7ja1 documentation - 5.1. 真理値テスト
オブジェクトのブール値を確認するには、組み込み関数 bool() を使うと良い。
>>> value = 'abcd' >>> bool(value) True >>> value = '' >>> bool(value) Falseブール演算子
ブール演算子としては、or , and , not が存在する。各演算子の働きと優先順位は次のようになる。
以下にブール演算子を示します。優先度の低いものから順に並んでいます。
演算 結果 注釈 x or y x が偽なら y, そうでなければ x (1) x and y x が偽なら x, そうでなければ y (2) not x x が偽なら True, そうでなければ False (3)
注釈 (1) これは、短絡的な演算子であり、一つめの引数が False のときにのみ、二つめの引数を評価します。 (2) これは、短絡的な演算子であり、一つめの引数が True のときにのみ、二つめの引数を評価します。 (3) not は非ブール演算子よりも低い演算優先度なので、 not a == b は not (a == b) と評価され、a == not b は構文エラーとなります。 and と or を試してみる。
>>> 'abcd' and 'efgh' 'efgh' >>> '' and 'efgh' ''>>> 'abcd' or 'efgh' 'abcd' >>> '' or 'efgh' 'efgh'and と or では全く逆の動きをするのがわかる。
ブール演算子を使った三項式
and と or のブール演算子の性格を利用して、三項式を作ることができる。次のように組み合わせる。
条件 and 真の場合の値 or 偽の場合の値試してみる。
>>> a = 'abcd' >>> b = 'efgh' >>> True and a or b 'abcd' >>> False and a or b 'efgh'三項演算子のように動いた。しかしこの式には重大な欠陥がある。もし「真の場合の値」が偽(False)だったら、どうなるか?。
>>> a = '' >>> b = 'efgh' >>> True and a or b 'efgh' >>> False and a or b 'efgh'条件に関わりなく、同じ結果になってしまう。or演算子は False or b の場合、変数 b を返すため、このような結果になる。この問題を回避するためには、「真の場合の値」をリストもしくはタプル値にすればよい。
>>> a = '' >>> b = 'efgh' >>> True and [a] or b [''] >>> False and [a] or b 'efgh' >>> True and (a,) or b ('',) >>> False and (a,) or b 'efgh'変数 a は False でもリストもしくはタプルは空ではないため、Falseにはならない。ただ、変数 a を返す時はリスト・タプル値が返ってきてしまうため、次のように変更する。
>>> a = '' >>> b = 'efgh' >>> (True and [a] or [b])[0] '' >>> (False and [a] or [b])[0] 'efgh' >>> (True and (a,) or (b,))[0] '' >>> (False and (a,) or (b,))[0] 'efgh'これで上手く動くようだ。
まとめると、ブール演算子を利用した三項式は次のようになる。
■ 「真の場合の値」が偽(False)になる可能性がない場合
条件 and 真の場合の値 or 偽の場合の値■ 「真の場合の値」が偽(False)になる可能性がある場合
(条件 and [真の場合の値] or [偽の場合の値])[0]もしくは(条件 and (真の場合の値,) or (偽の場合の値,))[0]ちなみに上の例を、(ブール演算を利用しない)三項演算子で書くと次のようになる。
>>> a = '' >>> b = 'efgh' >>> a if True else b '' >>> a if False else b 'efgh'三項演算子を使用した方が、なにかと簡単で安全ですね。
参考
Dive into Python 5.4. - 4.6.1.and−or トリックの使い方
紫藤のページ - 2.1. 三項演算子