LoginSignup
0
0

More than 5 years have passed since last update.

CS61A: Priority of Boolean Operators: and, or and not

Last updated at Posted at 2016-02-02

Labの問題よりBoolean関数について優先順位があったこと自体知らなかったので備忘録の意味でメモ。

and, or and not

pythonではこの3つのBoolean Operatorをサポートしている。

and evaluates to True only if both operands evaluate to True. If at least one operand is False, then and evaluates to False. or evaluates to True if at least one operand evaluates to True. If all operands are False, then or evaluates to False.

と書いてあるがTrue/Falseの値については「プログラマの数学」2章メモ#2 論理積、論理和、ド・モルガンの法則、ベン図、カルノー図、3値論理などでより詳細に書いたのでそちらを参考にしたほうが分かりやすいかもしれない。

Priority

結論から言うと優先順位はnot > and > orという順番らしい。よってたとえばTrue and not False or not True and Falseをevaluationすると(True and (not False)) or ((not True) and False)となるはずだ。ちなみにこれはTrue判定になるはず。詳しくはここを参考に。

Truthiness

Pythonの大きな特徴として「全てのオブジェクトをTrueもしくはFalse valueとして解釈することが出来る」というものがある。例えばwhileifTrue判定が出て初めて処理を始める。ということであらゆる種類のデータを扱うときに「どのようにしてTruthiness(=the quality of being felt to be true, even if not necessarily true)がpython内で定義されているのか」を知るのは非常に大切。

以下の関数を使えば簡単に調べることが可能。

def truthChecker(some_value):
    if some_value:
        print("YAY")
    else:
        print("NAY")

def noneChecker(some_value):
    if some_value is not None:
        print("YAY")
    else:
        print("NAY")

>>> checks_for_truth("apples"), checks_for_none("apples")
YAY!
YAY!
>>> checks_for_truth([]), checks_for_none([])
BOO!
YAY!
>>> checks_for_truth(""), checks_for_none("")
BOO!
YAY!
>>> checks_for_truth(15), checks_for_none(15)
YAY!
YAY!
>>> checks_for_truth(0), checks_for_none(0) # okay, seeing a pattern
BOO!
YAY!
>>> checks_for_truth(-10), checks_for_none(-10)
YAY!
YAY!
>>> checks_for_truth(None), checks_for_none(None)
BOO!
BOO!

要点だけまとめると

literals Falthy? None?
[] yep nope
"" yep nope
0 yep nope
None yep yep

Falsey valueだからといって必ずしもFalseを返すわけではないということ。

>>> [] and 1/0
[]

最初の[]Falseの時点で[]が全体の値となる。1/0をevaluateする前に[]を返してしまっているのでエラーを吐かない。詳しくは一番下を参考に。

Short-cuitという名の"Laziness"

>>> 'a' == ('a' or 'b')
True
>>> 'b' == ('a' or 'b')
False
>>> 'a' == ('a' and 'b')
False 
>>> 'b' == ('a' and 'b')
True

個人的に一見直感に反する答えが出てきたと思ったがよーく考えると納得がいく。

全体の流れ

ざっくり言うとこんな感じ。

Screen Shot 2016-02-09 at 9.48.40 PM.png

Screen Shot 2016-02-09 at 9.49.14 PM.png

要点は以下のとおり:

The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.

The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.

(Note that neither and nor or restrict the value and type they return to False and True, but rather return the last evaluated argument. This is sometimes useful, e.g., if s is a string that should be replaced by a default value if it is empty, the expression s or 'foo' yields the desired value. Because not has to create a new value, it returns a boolean value regardless of the type of its argument (for example, not 'foo' produces False rather than ''.)

  1. 括弧内の値をbool()してTrue/False判定を行う。以下の表に従ってまず括弧内の値がそもそもTrue/Falseかを確かめる。
  2. andorでそれぞれ処理を行う。
  3. 返ってきた値を左側の値と比較して(上の例題に従えば==なので)True/Falseで値を出す。
True False
1 0
#s other than 0 The string 'None'
Nonempty strings Empty strings
Nonempty lists Empty lists
Nonempty dictionaries Empty dictionaries

orexpressionの動き

Screen Shot 2016-02-09 at 8.46.56 PM.png

  1. 最初の(括弧内の)ひとつ目の値をとりTrue/False判定を行う。Trueの場合は2へ。Falseの場合は3へ。
  2. (1つめがTrueの場合)は残りの値をチェックせずに1つ目の値をそのまま返す。理由はorexpressionの特徴より(片方の値がTrueならば全体もTrueになるからである)。(例: 'a' == (True or False)は最初の値TrueTrue判定を出すのでTrueが括弧内全体の値として返される。よって'a' == TrueFalseとなりFalseを返す)
  3. (1つめがFalseの場合)は2番目と進みどこかでTrueを見つけた瞬間2に戻る。全てFalseの場合はShort-circuitingにより括弧全体の値がexpressionの中の(true or false関係なく)右の値となる。詳しくは一番下の追記を参考に。
>>> False is ('a' == ('' or  None or 0)) # ('' or  None or 0)全体の値がFalseなので'a' == False (which returns False)は究極False is Falseと同じなのでTrueになる
True
>>> False is ('a' == ('' or  None or 'a')) # ('' or  None or 'a')全体の値が'a'なのでFalse is ('a' == 'a')つまりFalse is Trueとなり結果Falseとなる。
False


if the first value is evaluated as false Python checks the second half and returns that value. That second half determines the truth value of the whole expression since the first half was false.

この振る舞いをshort circuitといってpythonがブーリアン値に対して行う反応らしい。

This "laziness" on the part of the interpreter is called "short circuiting" and is a common way of evaluating boolean expressions in many programming languages.

>>> 'a' == (False or 'a')
True

andexpressionの動き

Screen Shot 2016-02-09 at 8.43.03 PM.png

andexpressionも似たような動きをする。
1. 括弧内の一つ目の値がTrue判定でも(orのようにすぐTrue判定を出さずに)残りの値全てをチェックする。これはandexpression特有の動き(andは両方共TrueにならないとTrue値を返さないため)。どこかでfalse値を返した瞬間、残りを調べずに全体をFalseとして返す。
2. 括弧内の値がすべてTrue判定になった場合は最後の値を全体の値として返す。

>>> False is ('a' == ('a' and 1 and 9 and 'b'))
True
>>> False is ('a' == ('a' and 1 and 9 and 'a'))
False

'a' == ('a' and 1 and 2 and 'c' and 'd' and None and 'a') #NoneはFalse valueなので`a`を調べずに括弧内全体の値をFalseとして返す。
False
'a' == ('a' and 1 and 2 and 'c' and 'd' and 'a') #全部True valueなので最後の'a'が括弧内全体の値として返される。
True

orandまとめ

  1. orは括弧内のいづれかがTrueだった場合はそのTrue判定を出した値が括弧全体の値として出される。括弧内の値全てがFalse判定を下した場合は自動的にFalseとなる(=Short-Circuiting)
  2. andは1番目がTrueならば2番目に行く...(最後まで確認しに行く)。全てTrueならば括弧内の最後の値(一番右)を返す。括弧内の内いづれかがFalseの時点で全体の値が(True/False関係なく)一番左の値が全体のexpressionの値となる。(=Short-circuting)。
'a' == ('' or None or '' or 0 or [] or '' or 'a')
True
'a' == ('' or None or '' or 0 or [] or '' or 'b' or {}) # 左から順番に見ていき'b'がTrue値だと分かったので{}を判定せずに'b'を全体の値として出す。
False
'a' == ('a' and 'a' and 'a')
True
'a' == ('a' and 'a' and '')
False
'a' == ('a' and 'a' and False)
False
'a' == ('a' and 'b' and True and True) #since 'a' == True returns False
False
'a' == ('a' and 1 and 'a' and 9 and 9)
False
'a' == ('a' and 1 and 'a' and 9 and 'a')
True

andの場合は括弧の中にFalse値が入ってる時点で速攻でFalse判定を返す。orは最初の一個がTrueならが他関係なくその最初の値が全体の値として持っていかれる

ではこれは何を返すだろうか?

>>> 'a' == ('a' or None and 0)

上で紹介したPriorityによりNone and 0を先にTrue/False判定する。結果Falseの値が返ってきて'a' == ('a' or False)となりTrueが返ってくる。

>>> 'a' == ('a' or None and 0)
True

この理論に従えば

>>> 'a' == ('b' or None or 0)
False

となるはず。

ちなみに

>>> 'a' == ('b' and 'a' or 0)
True

ということは

>>> 'a' == ('a' and 'b' or 0)
False

になるのも容易にわかるはず。

追記

学校のラボの宿題を解いていて疑問に思ったことと、先生からのレスポンスをまとめておく。

>> False or 0 
0
how come 0 evaluates to True when bool(0) evaluates to False?

「0の値はbool(0) # Falseなので上の問題は一般化すればFalse or False。よって返ってくる値は0ではなくてFalseになるだろう」というのが俺の予想だったのですが、どうやら間違っていたようです。

Take this longer expression for example:
 
False or False or False or 0 
Once it gets to the last value - the value of the entire expression is dependent on it. If the last value is "truthy" (meaning bool(value) is True) - then the entire expression is "truthy". If the last value is falsey - then the entire expression is falsey. So with that in mind, python can just use the last value directly.

Here's another way to think about it: 
Is False Truthy? Nope. 
Is the second False Truthy? Nope. 
Is the third False Truthy? Nope. 
I've gotten to the last value - well there's no point figuring out if this is truthy or not. At this point the entire expression is dependent on this last value. Might as well just return that as the value. 

どうやらorの時は最後以外全ての値がFalseとなると最後の値のTruthiness/Falseinessに関係なく最後の値を出すようになっているらしいです。

例えば

>>> print(False or False or False or None)
None

False判定されてそれがこのexpressionの値になると思っていたのですがどうやら最後の値を返り値として出すようです。

>>> s = ""
>>> s or "foo"
'foo'
>>> s and "foo"
''

参考にしたリンク

0
0
0

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