web-dev-qa-db-ja.com

なぜPythonでは0、0 ==(0、0)が等しい(0、False)か

Python(Python 3.6でのみチェックしましたが、以前のバージョンの多くにも当てはまると思います):

(0, 0) == 0, 0   # results in a two element Tuple: (False, 0)
0, 0 == (0, 0)   # results in a two element Tuple: (0, False)
(0, 0) == (0, 0) # results in a boolean True

しかし:

a = 0, 0
b = (0, 0)
a == b # results in a boolean True

2つのアプローチで結果が異なるのはなぜですか?等価演算子はタプルを異なる方法で処理しますか?

116

最初の2つの式は両方ともタプルとして解析されます。

  1. (0, 0) == 0False)、その後に0が続きます
  2. 0、その後に0 == (0, 0)が続きます(これはまだFalseです)。

式は、等号演算子と比較したカンマ区切りの相対的な優先順位のため、そのように分割されます:Pythonは、2つの式を含むタプルを参照します。タプル。

しかし、3番目の例では、a = 0, 0cannotはタプルになります。 Tupleは値のコレクションであり、同等性テストとは異なり、Pythonでは割り当てに値がありません。割り当ては式ではなく、ステートメントです。 Tupleまたは他の周囲の式に含めることができる値はありません。タプルとして解釈を強制するために(a = 0), 0のようなものを試みた場合、構文エラーが発生します。 a = 0, 0の唯一の有効な解釈として、変数へのTupleの割り当て(a = (0, 0)を記述することでより明示的にすることができます)を残します。

155
Mark Reed

3つすべてのインスタンスで表示されるのは、言語の 文法仕様 の結果であり、ソースコードで検出されたトークンを解析して解析ツリーを生成する方法です。

この低レベルのコードを見ると、内部で何が起こるかを理解するのに役立ちます。これらのpythonステートメントを取得してバイトコードに変換し、disモジュールを使用して逆コンパイルできます。

ケース1:(0, 0) == 0, 0

>>> dis.dis(compile("(0, 0) == 0, 0", '', 'exec'))
  1           0 LOAD_CONST               2 ((0, 0))
              3 LOAD_CONST               0 (0)
              6 COMPARE_OP               2 (==)
              9 LOAD_CONST               0 (0)
             12 BUILD_Tuple              2
             15 POP_TOP
             16 LOAD_CONST               1 (None)
             19 RETURN_VALUE

(0, 0)は最初に0と比較され、Falseと評価されます。次に、この結果と最後の0でTupleが構築されるため、(False, 0)が取得されます。

ケース2:0, 0 == (0, 0)

>>> dis.dis(compile("0, 0 == (0, 0)", '', 'exec'))
  1           0 LOAD_CONST               0 (0)
              3 LOAD_CONST               0 (0)
              6 LOAD_CONST               2 ((0, 0))
              9 COMPARE_OP               2 (==)
             12 BUILD_Tuple              2
             15 POP_TOP
             16 LOAD_CONST               1 (None)
             19 RETURN_VALUE

タプルは、最初の要素として0で構築されます。 2番目の要素については、最初の場合と同じチェックが行われ、Falseと評価されるため、(0, False)が取得されます。

ケース3:(0, 0) == (0, 0)

>>> dis.dis(compile("(0, 0) == (0, 0)", '', 'exec'))
  1           0 LOAD_CONST               2 ((0, 0))
              3 LOAD_CONST               3 ((0, 0))
              6 COMPARE_OP               2 (==)
              9 POP_TOP
             10 LOAD_CONST               1 (None)
             13 RETURN_VALUE

ご覧のとおり、これら2つの(0, 0)タプルを比較し、Trueを返すだけです。

68
cs95

問題を説明する別の方法:あなたはおそらく辞書リテラルに精通している

{ "a": 1, "b": 2, "c": 3 }

および配列リテラル

[ "a", "b", "c" ]

およびタプルリテラル

( 1, 2, 3 )

しかし、あなたが気付いていないのは、辞書や配列リテラルとは異なり、タプルリテラルの周りに通常見られる括弧はリテラル構文の一部ではないことです 。タプルのリテラル構文は、コンマで区切られた一連の式です。

1, 2, 3

Pythonの正式な文法 )の言語の「exprlist」。

さて、あなたは配列リテラルに何を期待しますか

[ 0, 0 == (0, 0) ]

評価する?それはおそらくもっと似ているようですshouldと同じ

[ 0, (0 == (0, 0)) ]

もちろん[0, False]と評価されます。同様に、明示的に括弧で囲まれたTupleリテラルを使用

( 0, 0 == (0, 0) )

(0, False)を取得することは驚くことではありません。ただし、括弧はオプションです。

0, 0 == (0, 0)

同じことです。そして、それが(0, False)を取得する理由です。


タプルリテラルを囲むかっこがオプションである(why)と思っている場合、それはそのように破壊的な割り当てを記述する必要があるためです。

(a, b) = (c, d) # meh
a, b = c, d     # better
20
zwol

アクションが実行される順序の前後に括弧をいくつか追加すると、結果をよりよく理解できる場合があります。

# Build two element Tuple comprising of 
# (0, 0) == 0 result and 0
>>> ((0, 0) == 0), 0
(False, 0)

# Build two element Tuple comprising of
# 0 and result of (0, 0) == 0 
>>> 0, (0 == (0, 0))
(0, False)

# Create two tuples with elements (0, 0) 
# and compare them
>>> (0, 0) == (0, 0) 
True

コンマは個別の式に使用されます(もちろん、括弧を使用して異なる動作を強制できます)。リストしたスニペットを表示するとき、カンマ,はそれを区切り、評価される式を定義します。

(0, 0) == 0 ,   0
#-----------|------
  expr 1      expr2

タプル(0, 0)も同様の方法で分類できます。コンマは、リテラル0で構成される2つの式を区切ります。

最初のPythonでは、次の2つのタプルを作成しています。

  1. (0, 0) == 0、これはFalseに評価されます
  2. 定数0

2番目の方法では、逆になります。

6
kindall

この例を見てください:

r = [1,0,1,0,1,1,0,0,0,1]
print(r==0,0,r,1,0)
print(r==r,0,1,0,1,0)

その後の結果:

False 0 [1, 0, 1, 0, 1, 1, 0, 0, 0, 1] 1 0
True 0 1 0 1 0

次に、例の最初の数値(0およびr)と比較します。

0
Emad Saeidi