121

I'm testing the tuple structure, and I found it's strange when I use the == operator like:

>>>  (1,) == 1,
Out: (False,)

When I assign these two expressions to a variable, the result is true:

>>> a = (1,)
>>> b = 1,
>>> a==b
Out: True

This questions is different from Python tuple trailing comma syntax rule in my view. I ask the group of expressions between == operator.

Community
  • 1
  • 1
Pythoner
  • 5,265
  • 5
  • 33
  • 49
  • 16
    Looking at a [previous question](http://stackoverflow.com/questions/37312512/whats-the-difference-between-1-and-1-in-python) by the OP just 2 hours ago, It seems wonderful (or strange) that how just framing of a question differently can lead to different results (and acceptance among the community). – AKS May 19 '16 at 04:49
  • 24
    @AKS These are different qestions – kmaork May 19 '16 at 07:02
  • 7
    @AKS While the questions are marginally different here, I agree completely with your point. Herd effect aka HNQ. – Insane May 19 '16 at 11:12
  • @AKS These questions are different. The second is about expressions group and first is about tulle. I think it is acceptable to have two questions from same topic. – Pythoner May 19 '16 at 14:34
  • 5
    @PythonNewHand Indeed, it is completely acceptable. That's why I added that _framing a question differently_. – AKS May 19 '16 at 14:37
  • 3
    @CiroSantilli巴拿馬文件六四事件法轮功 how do you figure? I skimmed those answers and saw nothing that seemed to cover this particular situation. – Dan Getz May 20 '16 at 01:27

3 Answers3

157

This is just operator precedence. Your first

(1,) == 1,

groups like so:

((1,) == 1),

so builds a tuple with a single element from the result of comparing the one-element tuple 1, to the integer 1 for equality They're not equal, so you get the 1-tuple False, for a result.

Tim Peters
  • 67,464
  • 13
  • 126
  • 132
  • 62
    Not really, but 1-tuples have odd syntax. In general, you'd be far more surprised if, e.g., `1+2, 2==3, 4*7` did _not_ group as `(1+2), (2==3), (4*7)`. In practice, 1-tuples are hardly ever used (well, outside of StackOverflow questions ;-) ). – Tim Peters May 19 '16 at 03:36
  • 6
    Perhaps "unexpected" would have been a better word to use than "strange." I feel a bit like I'm looking at [one of those drawings that can be two things, depending on your perspective and focus](http://www.today.com/pets/rabbit-or-duck-124-year-old-drawing-has-both-if-t73606). The equality operator is so large compared to the commas, it's easy to focus on it and assume the result will be `True`/`False`. Now that I understand what's happening, it's perfectly obvious and reasonable. – skrrgwasme May 19 '16 at 03:46
  • 31
    And now you know what the "Zen of Python" means by saying that the one obvious way to do it "may not be obvious at first unless you're Dutch" ;-) – Tim Peters May 19 '16 at 03:50
  • 7
    It's a little bit confusing when you read the doc and see that what makes a tuple is the comma, not the parentheses! So in this statement the comma in the right hand is not considered as a part of the test but it's considered as a separator! Unexpected behavior! – Ikra_5 May 19 '16 at 11:56
  • 1
    @TimPeters: "In practice, 1-tuples are hardly ever used" I use them all the time ☺. To extract the item from a list that *should* have only one element. `(e,) = a_list`. That code will crash, as desired, if the list hasn't exactly one element. It's a very lazy way to asser that `len(a_list) == 1` – Aaron McDaid May 19 '16 at 13:17
  • @skrrgwasme I would argue that PHP's left-associative ternaries are even stranger. `a?b:c?d:e` is interpreted as `(a?b:c)?d:e`. – John Dvorak May 20 '16 at 01:45
  • 3
    Common advice about expressions is "when in doubt, use parentheses". Following that, it's good to put parentheses around all one-tuples, even though they are not part of the tuple syntax. – nigel222 May 24 '16 at 09:12
90

Other answers have already shown you that the behaviour is due to operator precedence, as documented here.

I'm going to show you how to find the answer yourself next time you have a question similar to this. You can deconstruct how the expression parses using the ast module:

>>> import ast
>>> source_code = '(1,) == 1,'
>>> print(ast.dump(ast.parse(source_code), annotate_fields=False))
Module([Expr(Tuple([Compare(Tuple([Num(1)], Load()), [Eq()], [Num(1)])], Load()))])

From this we can see that the code gets parsed as Tim Peters explained:

Module([Expr(
    Tuple([
        Compare(
            Tuple([Num(1)], Load()), 
            [Eq()], 
            [Num(1)]
        )
    ], Load())
)])
Community
  • 1
  • 1
wim
  • 338,267
  • 99
  • 616
  • 750
  • 1
    Another useful tool is `dis` -- In this case, you'd see two `LOAD_CONST` with different values (`(1,)` and `1`) and a `BUILD_TUPLE` opp-code. – mgilson May 20 '16 at 21:38
13

When you do

>>> (1,) == 1,

it builds a tuple with the result from comparing the tuple (1,) with an integer and thus returning False.

Instead when you assign to variables, the two equal tuples are compared with each other.

You can try:

>>> x = 1,
>>> x
(1,)
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
mng
  • 393
  • 2
  • 10