title: python tuple comparison, 'less than' revisited (2.7)
body: <p>I want to understand Python's behavior for tuple comparison operators, specifically <strong>&lt;</strong> (the less-than operator).</p>
  
  <hr>
  
  <p>edit: Now I get it, thank you Jaroslaw for a clear answer.</p>
  
  <p>My error was thinking 1) "Lexicographical comparison" was a synonym for "string compare",
  and 2) thinking that the "string compare logic" applied to each element of the tuples being compared instead of at the tuple-level.  Which yields valid behavior for <strong>==</strong> but not so much for <strong>&lt;</strong>.</p>
  
  <p>On the off chance anyone else gets stuck on the distinction.</p>
  
  <blockquote>
    <p><em>excerpt from wikipedia (emphasis added)</em><a href="https://en.wikipedia.org/wiki/Lexicographical_order" rel="nofollow noreferrer">4</a>: ...lexicographical order ... is a <strong>generalization</strong> 
    of the way the alphabetical order of words is based on the alphabetical order of their component letters.
    This generalization consists primarily in defining a <strong>total order</strong> over the <strong>sequences ...  of
    elements of a finite totally ordered set</strong>, often called alphabet.</p>
  </blockquote>
  
  <p>original question text follows...</p>
  
  <hr>
  
  <p>Wait, you say, hasn't this been asked before?
  Yes... and pretty well answered for <strong>==</strong> (equality).
  I want to understand why <strong>( 1, 2 ) &lt; ( 1, 3 )</strong> yields <strong>True</strong> (note the <strong>&lt;</strong> less than operator, code example below).  This is likely just a python-newbie error on my part, but I am having trouble finding it.</p>
  
  <p>I've read some other questions about how tuple comparisons involves "lexicographic comparisons of the respective elements form each tuple."</p>
  
  <p><strong>Question:</strong> <a href="https://stackoverflow.com/questions/33586081/python-tuple-comparison-odd-behavior">python-tuple-comparison-odd-behavior</a>:  This question is about using the <strong>in</strong> operator, I'm interested in <strong>&lt;</strong> (less than), not so much the behavior of <strong>in</strong> (at least not yet).</p>
  
  <p><strong>Question:</strong> <a href="https://stackoverflow.com/questions/5292303/python-tuple-comparison">python-tuple-comparison</a>:  For this one the answer says (emphasis added):</p>
  
  <blockquote>
    <p><em>excerpt from Answer:</em> Tuples are compared position by position: the first item of first
    tuple is compared to the first item of the second tuple; if they are
    <strong>not equal</strong>, this is the result of the comparison, else the second item
    is considered, then the third and so on.</p>
  </blockquote>
  
  <p>Which I understand for <strong>==</strong> comparisons.
  edit: *thought I understood</p>
  
  <p>To generalize to all comparison operators I would modify the answer to be <em>something</em> like this:</p>
  
  <blockquote>
    <p>... the first item of first tuple is compared to the
    first item of the second tuple; if the comaprison yields False
    then the result of the tuple comaprison is also False.  Otherwise
    the comparison continues with the remaining items....
    edit: this was wrong. Subtly wrong though, worked for <strong>==</strong> but not other relational operators.</p>
  </blockquote>
  
  <p>I am having trouble seeing how that works for <strong>&lt;</strong> (less than) comparisons.
  The <a href="https://docs.python.org/2.7/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange" rel="nofollow noreferrer">python documentation</a> they link to (modified to point to 2.7) also talks about this in terms of equality, not less than - again, emphasis added:</p>
  
  <blockquote>
    <p><em>excerpt from python docs:</em> Sequence types also support comparisons. In particular, tuples and
    lists are compared lexicographically by comparing corresponding
    elements. This means that to <strong>compare equal</strong>, every element must <strong>compare
    equal</strong> and the two sequences must be of the same type and have the same
    length. (For full details see Comparisons in the language reference.)
    edit: at this point when writing up my original question I had tunnel vision on 'equality'.</p>
  </blockquote>
  
  <p>I found nothing helpful in the The Comparisons language reference; it doesn't touch on why <strong>( 1, 2 ) &lt; ( 1, 3 )</strong> yields <strong>True</strong> when the comparison operator seems like it should yield False for the first pair of elements.</p>
  
  <p>The following is some example output of a toy test program; <em>most</em> of it works as I would expect.  Please note the 2 embedded questions.</p>
  
  <p>Ouput from "tcomp.py" (source below).</p>
  
  <pre><code>$ python tcomp.py
  tcomp.py
  version= 2.7.12
  
  ---  empty tuples, intuitive, no surprises  ---
  ()  ==  ()  :  True
  ()   &lt;  ()  :  False
  ()   &gt;  ()  :  False
  
  ---  single-item tuples, equal values: intuitive, no surprises  ---
  (1,)  ==  (1,)  :  True
  (1,)   &lt;  (1,)  :  False
  (1,)   &gt;  (1,)  :  False
  
  ---  single-item diff: intuitive, no surprises  ---
  (1,)  ==  (2,)  :  False
  (1,)   &lt;  (2,)  :  True
  (1,)   &gt;  (2,)  :  False
  
  ---  double-item same: intuitive, no surprises  ---
  (1, 2)  ==  (1, 2)  :  True
  (1, 2)   &lt;  (1, 2)  :  False
  (1, 2)   &gt;  (1, 2)  :  False
  * Question: do a&lt;b and a&gt;b both yield False 
  * because Python short circuits on
  * a[0] &lt; b[0]    (and correspondingly a[0] &gt; b[0] )?
  * e.g. Python never bothers comparing second
  * elements: a[1] &lt; b[1]  (and, correspondinlgy, a[1] &gt; b[1] ).
  
  ---  double-item 1st=same 2nd=diff: ??? What is with a&lt;b ???
  (1, 2)  ==  (1, 3)  :  False
  (1, 2)   &lt;  (1, 3)  :  True
  (1, 2)   &gt;  (1, 3)  :  False
  * Question: Here I get the == comparison, that yields False like I would expect.
  * But WHAT is going on with the &lt; comparison?
  * Even comapring "lexicographically", how does a[0] &lt; b[0]
  * actually yield True ?
  * Is Python really  comparing a[0] &lt; b[0] ?
  * Because in my mental model that is the same as comparing: 1 &lt; 1
  * I kind of think 1 &lt; 1 is supposed to be False, even if Python
  * is comparing "1" &lt; "1"  (e.g. lexicographically).
  $ 
  </code></pre>
  
  <p>To add to the last "*Question" above, comapring <strong>a[0] &lt; b[0]</strong> lexicographically would be like comparing <strong>'1' &lt; '1'</strong> which still should be false, yes?</p>
  
  <p><strong>tcomp.py:</strong></p>
  
  <pre><code>import platform
  
  def tupleInfo( a, b, msg ):
     # using labels instead of eval-style stuff to keep things simpler.
     print
     print '--- ' , msg , ' ---'
     print a, ' == ', b, ' : ', a == b
     print a, '  &lt; ', b, ' : ', a  &lt; b
     print a, '  &gt; ', b, ' : ', a  &gt; b
  
  print 'tcomp.py'
  print 'version=', platform.python_version()
  
  # let's start with some empty tuples.
  e1 = tuple()
  e2 = tuple()
  tupleInfo( tuple( )         , tuple( )         , 'empty tuples,intuitive, no surprises' )
  tupleInfo( tuple( [ 1 ] )   , tuple( [ 1 ] )   , 'single-item tuples, equal values: intuitive, no surprises' )
  tupleInfo( tuple( [ 1 ] )   , tuple( [ 2 ] )   , 'single-item diff: intuitive, no surprises' )
  tupleInfo( tuple( [ 1, 2 ] ), tuple( [ 1, 2 ] ), 'double-item same: intuitive, no surprises' )
  
  print '* Question: do a&lt;b and a&gt;b both yield False '
  print '* because Python short circuits on'
  print '* a[0] &lt; b[0]    (and correspondingly a[0] &gt; b[0] )?'
  print '* e.g. Python never bothers comparing second'
  print '* elements: a[1] &lt; b[1]  (and, correspondinlgy, a[1] &gt; b[1] ).'
  
  
  tupleInfo( tuple( [ 1, 2 ] ), tuple( [ 1, 3 ] ), 'double-item 1st=same 2nd=diff: ??? What is with a&lt;b ???' )
  
  print '* Question: Here I get the == comparison, that yields False like I would expect.'
  print '* But WHAT is going on with the &lt; comparison?'
  print '* Even comapring "lexicographically", how does a[0] &lt; b[0]'
  print '* actually yield True ?'
  print '* Is Python really  comparing a[0] &lt; b[0] ?'
  print '* Because in my mental model that is the same as comparing: 1 &lt; 1'
  print '* I kind of think 1 &lt; 1 is supposed to be False, even if Python'
  print '* is comparing "1" &lt; "1"  (e.g. lexicographically).'
  </code></pre>