

Pythonで `print(0 or (1 and 2))` と入力した場合、返ってくる値は 2 ですが、`print(0 or (2 and 1))`
とした場合、返ってくる値が 1 になるのはなぜですか？ヘルプを参照したのですがいまいちしっくり来ませんでした。

たくさんのパターンを試し、Trueの場合一番右に位置する数字が返ってくることまではわかったのですが、そうなる訳を知りたいです。

お答えいただけると幸いです。


CC BY-SA 4.0
2020-09-18T07:28:36.037
70515
2020-09-19T05:48:44.153
2020-09-19T05:48:44.153
3060
38330
question
python python3
Python の 'and' や 'or' で、左右への値の記述方法によって結果が異なるのはなぜ？


Python 言語リファレンス  
<https://docs.python.org/ja/3/reference/expressions.html#boolean-operations>  
の  
6.11. ブール演算 (boolean operation)  
に

> 式 x and y は、まず x を評価します; x が偽なら x の値を返します; それ以外の場合には、 y の値を評価し、その結果を返します。

と規定されています。


CC BY-SA 4.0
2020-09-18T07:42:45.903
70516
2020-09-18T09:01:35.157
2020-09-18T09:01:35.157
41756
41756
70515
answer


**回答**

> print(0 or (1 and 2))と入力した場合、返ってくる値は2ですが、  
>  print(0 or (2 and 1))とした場合、返ってくる値が1になるのはなぜですか？

`0 or`の0(偽)では式全体の真偽が確定せず、評価が継続します。  
`or`に続く`(1 and 2)`または`(2 and 1)`の評価は、  
`1 and`の1が真なのでは真偽の評価が確定せず、評価が継続します。  
`2 and`の2も真なので同様に評価が継続します。  
`and`に続く値が最後ですので、式全体の評価が確定し、結果は`andに続く値`になります。

どうしてそうなのかはlehshellさんの回答にあるとおり、Pythonの文法[6.11. ブール演算 (boolean
operation)](https://docs.python.org/ja/3/reference/expressions.html#boolean-
operations)に説明があります。

* * *

**確かめたこと**  
結構長くなりました、よろしければお付き合いください。

まず、`1 and 2`と`2 and 1`について確かめてみます。

[code]

    >>> print(1 and 2)
    2
    >>> print(2 and 1)
    1
    >>> 
    
[/code]

上のコードは`and`に続く値が表示されているようです。  
試しに`and`の後の数値を変えてみても同様の結果になります。

[code]

    >>> print(1 and 100)
    100
    >>> print(2 and 100)
    100
    
[/code]

上のコードは`and`の前の数値に関係なく`and`に続く値が表示されいるようです。

以下のコードを実行してみます。

[code]

    >>> print(0 and 100)
    0
    >>> print(0 and 200)
    0
    
[/code]

`and`の前の数値を0にすると0が表示されます。  
この例では`and`に続く値には関係なく0が表示されているようです。

今度は`and`に続けてエラーとなる式を書いてみます。

[code]

    >>> print(0 and 1/0)
    0
    >>> print(1 and 1/0)
    Traceback (most recent call last):
      File "<pyshell#94>", line 1, in <module>
        print(1 and 1/0)
    ZeroDivisionError: division by zero
    >>> print(2 and 1/0)
    Traceback (most recent call last):
      File "<pyshell#95>", line 1, in <module>
        print(2 and 1/0)
    ZeroDivisionError: division by zero
    
[/code]

`and`の前が0のときエラーとならず0が表示されますが、`and`の前が0以外だとエラーとなります。  
この振る舞いの違いは`and`の前の値を論理的に評価した結果の違いによるようです。

数値を論理値(True or False)として評価してみると以下の結果となりました。

[code]

    >>> bool(0)
    False
    >>> bool(1)
    True
    >>> bool(2)
    True
    
[/code]

`and`の前の値を論理値として評価し、  
Falseだったら式の真偽値が確定し、評価を終了。  
Trueだったら式の真偽値が確定しないので、`and`に続く式を評価しているようです。

真偽の評価は真偽が確定するまで続き、確定した時点の値が結果となるようです。

* * *

次は`or‘について試してみます。

[code]

    >>> print(0 or 10)
    10
    >>> print(0 or 20)
    20
    >>> print(1 or 10)
    1
    >>> print(1 or 20)
    1
    >>> print(2 or 10)
    2
    >>> print(2 or 20)
    2
    
[/code]

この例では、  
`or`の前の項が偽(0)の場合は式の真偽が確定せず(次の評価で真になるかもしれない)、次の値の評価が行われます。  
`or`の前の項が真(この例では1または2)の場合は式の真偽が確定するので、結果は`or`の前の値となります。

この場合も、真偽の評価は真偽が確定するまで続き、確定した時点の値が結果となるようです。

* * *

**まとめ**  
論理式の評価は真偽が確定するまで継続し、真偽が確定したところで評価が終了し、そのとき評価していた対象が結果となるようです。


CC BY-SA 4.0
2020-09-19T01:56:28.303
70530
2020-09-19T04:16:43.980
2020-09-19T04:16:43.980
35558
35558
70515
answer