118 votes

Pourquoi en python 0, 0 == (0, 0) est égal à (0, faux)

En Python (j'ai vérifié uniquement avec Python 3.6 mais je pense que cela devrait également être valable pour les versions précédentes):

 (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
 

Mais:

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

Pourquoi le résultat diffère-t-il entre les deux approches? L'opérateur d'égalité gère-t-il les tuples différemment?

156voto

Mark Reed Points 23817

Les deux premières expressions à la fois analyser les tuples:

  1. (0, 0) == 0 (ce qui est False), suivie par l' 0
  2. 0, suivie par l' 0 == (0, 0) (ce qui est encore False de cette façon autour).

Les expressions sont répartis de cette façon en raison de la priorité relative de la virgule de séparation par rapport à l'opérateur d'égalité: Python voit un tuple contenant deux expressions, dont l'un se trouve être un test d'égalité, au lieu d'un test d'égalité entre deux n-uplets.

Mais dans le troisième exemple, a = 0, 0 ne peut pas être un n-uplet. Un tuple est une collection de valeurs, et contrairement à un test d'égalité, la cession n'a pas de valeur en Python. Une cession n'est pas une expression, mais une déclaration; il n'a pas une valeur qui peut être inclus dans un tuple ou toute autre expression englobante. Si vous avez essayé quelque chose comme (a = 0), 0 afin de forcer l'interprétation comme un n-uplet, vous aurez une erreur de syntaxe. Que les feuilles de l'attribution d'un n-uplet d'une variable qui pourrait être plus explicite par écrit a = (0, 0) – comme le seul valable interprétation de l' a = 0, 0.

68voto

coldspeed Points 111053

Ce que vous voyez dans tous les 3 cas, c'est une conséquence de la spécification de la grammaire de la langue, et la manière dont les pions rencontrés dans le code source sont analysés afin de générer l'arbre d'analyse.

Prendre un coup d'oeil à ce faible niveau de code devrait vous aider à comprendre ce qui se passe sous le capot. Nous pouvons prendre ces instructions python, les convertir en code octet, puis de les décompiler l'aide de l' dis module de:

Cas 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) est première par rapport à l' 0 d'abord évaluée False. Un tuple est alors construit avec ce résultat et dernier 0, de sorte que vous obtenez de l' (False, 0).

Cas 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

Un tuple est construit avec 0 comme le premier élément. Pour le deuxième élément, la même vérification est faite comme dans le premier cas et évaluée afin d' False, de sorte que vous obtenez de l' (0, False).

Cas 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

Ici, comme vous le voyez, vous êtes juste en comparant ces deux (0, 0) n-uplets et de revenir True.

20voto

Zack Points 44583

Une autre façon d'expliquer le problème: Vous êtes probablement familier avec le dictionnaire des littéraux

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

et littéraux de tableau

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

et de tuple littéraux

( 1, 2, 3 )

mais ce que vous ne réalisent pas est que, à la différence du dictionnaire et de la matrice de littéraux, entre parenthèses, vous avez l'habitude de voir autour d'un tuple littérale sont pas partie de la syntaxe littérale. La syntaxe littérale de tuples est simplement une suite d'expressions séparées par des virgules:

1, 2, 3

(un "exprlist" dans la langue de la grammaire formelle pour Python).

Maintenant, qu'attendez-vous le littéral de tableau

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

afin d'évaluer? Qui ressemble probablement beaucoup plus comme il devrait être le même que

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

ce qui bien sûr donne [0, False]. De même, avec une explicitement mis entre parenthèses tuple littérale

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

il n'est pas surprenant d'obtenir (0, False). Mais les parenthèses sont facultatives;

0, 0 == (0, 0)

c'est la même chose. Et c'est pourquoi vous obtenez (0, False).


Si vous vous demandez pourquoi les parenthèses autour d'un tuple littérale sont facultatifs, c'est en grande partie parce qu'il serait ennuyeux d'avoir à écrire déstructuration des affectations de cette façon:

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

17voto

Jim Points 8793

Ajout d'un couple de parenthèses autour de l'ordre dans lequel les actions sont réalisées pourraient vous aider à mieux comprendre les résultats:

# 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

La virgule est utilisée pour séparer des expressions (à l'aide de parenthèses, nous pouvons force comportement différent, bien sûr). Lors de l'affichage de l'extrait que vous avez énumérés, la virgule , va se séparer et définir ce que les expressions sont évaluées:

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

Le tuple (0, 0) peut également être ventilé de manière similaire. La virgule sépare deux expressions comportant des littéraux 0.

6voto

kindall Points 60645

Dans le premier, Python fait un tuple de deux choses:

  1. L'expression (0, 0) == 0 , qui correspond à False
  2. La constante 0

Dans le second cas, c'est l'inverse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X