11
'2'<'1'== False #False
('2'<'1')== False #True
'2'<('1'== False) #error

code in python3 we know operator precedence in python3 https://docs.python.org/3/reference/expressions.html#operator-precedence

wzf wu
  • 126
  • 5
  • 9
    Isn't `'2'<'1'== False` equivalent to `('2'<'1') and ('1'== False)` which is obviously false? – vc 74 Nov 05 '20 at 05:22
  • 4
    It's weird behavior, but maybe https://www.geeksforgeeks.org/chaining-comparison-operators-python/ helps – ymonad Nov 05 '20 at 05:25
  • 1
    You are trying to compare a string to a boolean, how it is possible? – ashraful16 Nov 05 '20 at 05:54
  • 1
    @Everyone python doesn't have concept of characters, it is a string of size 1 – Arsenic Nov 05 '20 at 06:20
  • @Arsenic my bad, I keep thinking statically all the time. – Everyone Nov 05 '20 at 06:22
  • You should consider adding C tag as well to the question. – Soner from The Ottoman Empire Nov 05 '20 at 06:53
  • I know nobody cares about this, so I'll add it as a comment. `'2'<'1'` isn't actually comparing string sizes. It takes each character, then compares its value to a character from the second string. If all characters are smaller than those in the second string, it will be true. When lengths do not match, it's padded (idk with what) and the pad is compared, for number character, pad is always smaller. To prove what I'm saying: `'0999' < '09999'` is `True` while `'1999' < '09999'` is `False` – Everyone Nov 05 '20 at 07:08
  • @Everyone When lengths do not match, it's padded (idk with what) ---> it is not right. – Soner from The Ottoman Empire Nov 05 '20 at 10:47
  • @snr what's right and how are they compared when lengths mismatch? – Everyone Nov 05 '20 at 23:12

3 Answers3

15

In case 1 :-

'2'<'1'== False

it is evaluated as '2'<'1' and '1' == False according to the operator chaining {thanks @ymonad to provide this link}

which will evaluated to be False

in case 2 :-

('2'<'1')== False

as () have higher precedence so will be evaluated first. so the expression will be reduced to False == False which will evaluate to be True

in case 3 :-

'2'<('1'== False)

first ('1' == False) is evaluated which is False but now the operation is '2'<False which is an illegal operation in python


EDIT:

To answer a question raised by @snr in the comment section

The vital question is why '1'== False is valid while '2'< bool is not

It is because the default behaviour for equality comparison (== and !=) is based on the identity of the objects, and as object False and object '1' does not share the same identity thus the result will be False

whereas a default behaviour of other comparison (<, >, <=, and >=) is not provided thus an attempt to do so raises TypeError


you can find this in documentation link provided by OP (under the heading value-comparisions)

Arsenic
  • 727
  • 1
  • 8
  • 22
  • 2
    Good answer, but who on earth thought it was a good idea for `a – Everyone Nov 05 '20 at 06:37
  • 2
    @Everyone that's true, this doesn't happen in other languages like C/C++ where we have different precedence for comparison operators. – Arsenic Nov 05 '20 at 06:41
  • 1
    I am not aware of any other language, or any other logic operations procedure, that would make such interpretation. A program should only do what you tell it to do. We usually say this statement to people who think their programs should behave like they wish, not what they told the programs to do. Yet here, it seems the program is doing what it wishes of its own, not what you told it to do. I am once again reminded why I keep getting away from this language every time I come back. – Everyone Nov 05 '20 at 06:43
  • 2
    Just for (maybe?) completeness, `'2'<'1'` is `False`, `'2'<'11'` is `False` as well. String comparison isn't actually doing length comparison as many sources claim. – Everyone Nov 05 '20 at 06:45
  • 3
    @Everyone, it all starts with a good intent, `3 < blah < 4` is equivalent to `3 < blah and blah < 4` with `blah` evaluated only once. You may be used to the C like syntax but I find this more intuitive for beginners. This syntax may be misleading though: `==` is also a comparison operator and can therefore be chained with other comparison operators like in the OP's example, producing counter intuitive expressions. – vc 74 Nov 05 '20 at 08:59
  • 2
    The vital question is why **'1'== False** is valid while **'2'< bool** is not. That's why I didn't answer the question simply. – Soner from The Ottoman Empire Nov 05 '20 at 09:07
  • @snr that's a nice question. I have answered it in the edited part of the post – Arsenic Nov 05 '20 at 11:17
  • @Arsenic False and object '1' does not share the same identity ?? If IT DOESN'T share what about '2'< bool value ? Did you miswrite? Even if so, could you explain both cases ? – Soner from The Ottoman Empire Nov 05 '20 at 12:52
  • @snr it's only equality/inequality operator whose default behaviour is to check for object identity if value comparison fails. there is not such rule for other comparison operators thus it don't know what to do if objects of different types are received. look at the documentation link provided at the end of answer to get a better picture of it. – Arsenic Nov 05 '20 at 16:03
  • (: It means I don’t know what s going on under the Iceberg. Thanks for the answer. – Soner from The Ottoman Empire Nov 05 '20 at 17:24
0

When python tries to do string < string then it turns into ascii and it orders it by alphabet order. https://careerkarma.com/blog/python-compare-strings/

By the way, 1 ascii is 49 and 2 ascii is 50

First case

'2'<'1'== False #False

it is evaluated as '2'<'1' and '1' == False which is False
because 50 < 49 and 1 == False -> False and False -> False

second case

('2'<'1')== False # True

it makes python do () first. (50 < 49) == False-> False == False -> True

third case

'2'<('1'== False) #error 

first ('1' == False) is evaluated which is False and you try to do '2'<False. And it get's an error.

Python Operator Precedence: https://www.mathcs.emory.edu/~valerie/courses/fall10/155/resources/op_precedence.html

David Hammen
  • 32,454
  • 9
  • 60
  • 108
ppwater
  • 2,315
  • 4
  • 15
  • 29
-2

I really tried to dig into but I can't get an answer which satisfies me. However, a person who has some time can walk through the following.

PyObject *tp_richcompare(PyObject *self, PyObject *other, int op); methods runs under the hood. Its implementation is here.

As far as I understand, it firstly checks whether both PyObjects are comperable by inspecting the object types by e.g.

(!Py_IS_TYPE(v, Py_TYPE(w)) &&
 PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v)) &&
 (f = Py_TYPE(w)->tp_richcompare) != NULL)  

As we can see also in your code, while <class 'str'> __eq__ <class 'int'> is meant to 'Yes, they are compatible with each other w.r.t. the comparison.', <class 'str'> __lt__ <class 'bool'> is the opposite. We are pretty sure that one of the last stations is here.

print(type(1))
print(type('1'))
print(type(False))
print(type('1' == 1))
print('1' == 1) #False <class 'str'> __eq__ <class 'int'>
print(('2' < '1')== False) #True
#print('2'<('1'== False))  <class 'str'> __lt__ (<class 'str'> __eq__ <class 'bool'>)
# (<class 'str'> __eq__ <class 'bool'>) returns <class 'bool'>, then as a result
# <class 'str'> __lt__  <class 'bool'> comparison is not implemented.

As a side note, its satisfactory answer, at least for me, must include detailed C explanations, not Pythonic