Pythonで「0、0 ==(0、0)」が「(0、False)」に等しいのはなぜですか?


118

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つのアプローチで結果が異なるのはなぜですか?等価演算子はタプルを別の方法で処理しますか?

回答:


156

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

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

等式演算子と比較したカンマ区切りの相対的優先順位のため、式はそのように分割されます。Pythonは2つの式を含むタプルを認識し、そのうちの1つはたまたま2つのタプル間の等価性テストではなく等価性テストです。

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

したがって、への割り当てに括弧がなくてもa、それとb値の両方が割り当てられる(0,0)ため、そうa == bなりますTrue


17
等式の評価はコンマ演算子の評価よりも優先されるため、コンマ演算子の方が同等性よりも優先順位が低いと言えます。同等性はコンマ演算子よりも優先順位が高くなります。しかし、これは常に混乱の元です。他の情報源が逆転する可能性があることを指摘したかっただけです。
tomsmeding 2017

2
代わりにとの,結合の強さを低くすることで、言い回しの混乱を避けることができ==ます。
アマロイ2017

4
コンマはありませんオペレータdocs.python.org/3.4/faq/...
Chris_Rands

48
ドキュメントは彼らが望むすべてのものを主張することができますが、それは問題ではありません。すべての演算子が独自のプロダクションを取得し、実装のどこにも明示的な「優先順位」がないように、パーサーを作成できますが、これらの構文単位が演算子であることを妨げるものではありません。実装固有の方法で「演算子」を再定義できます。 、それは明らかに彼らがPythonでやったことですが、それは用語の意味を変えません。カンマは事実上、タプルを生成する演算子です。その演算子性は、たとえば、相対的な優先順位が括弧によって影響される方法を示します。
マークリード

68

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でタプルが構築されます(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

ここでは、ご覧の(0, 0)とおり、これら2つのタプルを比較してreturnしていTrueます。


20

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

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

および配列リテラル

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

そしてタプルリテラル

( 1, 2, 3 )

ただし、辞書や配列のリテラルとは異なり、タプルリテラルの周りに通常表示される括弧は、リテラル構文の一部ではないことを理解していないことに注意してください。タプルのリテラル構文は、コンマで区切られた一連の式です。

1, 2, 3

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

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

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

評価する?それはおそらく同じように見えるはずです

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

もちろんこれはに評価され[0, False]ます。同様に、明示的に括弧で囲まれたタプルリテラル

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

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

0, 0 == (0, 0)

同じことです。そしてそれがあなたが得る理由です(0, False)


なぜタプルリテラルの括弧がオプションであるのか疑問に思っているのであれば、それは主に、そのような方法で構造化代入を記述しなければならないのは面倒だからです。

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

17

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

# 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)も同様の方法で分解できます。コンマは、リテラルを構成する2つの式を区切ります0


6

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

  1. 次のよう(0, 0) == 0に評価される式False
  2. 定数 0

2つ目は逆です。


0

この例を見てください:

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)と比較します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.