Some comparisons are declared as not specified in Python 2.7:
The most important general rules for comparisons are in
The Python Language Reference chapter 5. Expressions / 5.9 Comparisons.
The first rules are the well known ones for comparison of numeric types (bool, int, long, float), strings (str, unicode), tuples and lists. The last two rules declare what is not specified:
- Mappings (dictionaries) compare equal if and only if their sorted (key, value) lists compare equal. [5] Outcomes other than equality are resolved consistently, but are not otherwise defined. [6]
- Most other objects of built-in types compare unequal unless they are the same object; the choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program.
Many specific rules are in Comparison chapter in The Python Standard Library / Built-in Types, referenced above in the question, and in docs about specific types like complex, Decimal or Fraction.
Order comparison is not supported for type complex and it should raise TypeError. Decimal type is compared by value. It is compatible with numbers.Number since Python 2.7. fractions.Fraction is also compared by value.
My reflection: If a relation of comparison can be arbitrary and can be not reproducible within two executions of the program on the same computer, then it is not useful to say about transitivity. All cases above where the order is explicitly not specified in Python 2 should raise TypeError in Python 3.
The transitivity or ordering of builtin types is known broken in Python 2.7 only between types where equivalency of values of different builtin types is implemented but they are not implemented equivalent to other types.
Example: broken transitivity in IronPython (inspired by Blender's comment and simplified):
>>> assert long(0) < 1.0 < [] < long(0) # 0 < 1; 'float' < 'list' < 'long'
Even the equivalency (==
), that looks simpler to decide, is also not always transitive. That breaks the transitivity of the operator (<=
). See examples in comments. (Thanks for fix) (Equivalency is not the identity. a is b
implies a == b
, but not vice-versa.)
Examples use many trivial user-defined classes, with names one-letter capital or lowercase:
class A(object): pass
class a(object): pass
...
class z(object): pass
Observation - Numbers
All numeric types have many naturally equivalent values in CPython and IronPython (and probably in all other implementations according docs)
>>> assert (False == 0 == 0L == 0.0 == 0 + 0j == Decimal('0') == Fraction(0, 1) <
... True == 1 == 1L == 1.0 == 1 + 0j == Decimal('1') == Fraction(1, 1))
Numeric types are ordered before all other types in CPython:
>>> assert 0 < 10**1000 < float('inf') < A() < Z() < a()
Numeric types are dispersed between other types in IronPython
>>> assert D() < decimal.Decimal('0') < E()
>>> assert F() < fractions.Fraction(0, 1) < G()
>>> assert b() < False < c() # bool
>>> assert c() < 0 + 0j < d() # complex
>>> assert f() < 0.0 < g() # float
>>> assert i() < 0 < j() # int
>>> assert l() < 0L < m() # long
Strings etc
str, bytearray and unicode have equivalent values
>>> assert bytearray('ab') == 'ab' == u'ab'
Nothing special in ordering to other types is used in CPython,
>>> assert b() < bytearray('ab') < c() # bytearray
>>> assert s() < 'ab' < t() # str
>>> assert u() < u'ab' < v() # unicode in CPython
In IronPython: The type unicode
behaves like str
. It is not strange because strings are implemented in .NET like unicode and the same is in IronPython.
>>> assert s() < u'ab' < t() # unicode in Iron Python like str
>>> unicode
<type 'str'>
x < y < z < x
gives True for OP's example. – Cormier2**200 < float('+inf') < [] < 2**200
– Capiasx < y < z < x
doesn't make it a transitivity counterexample.x < y < z and not x < z
does. – Crickx < y < z < x
holds and your relation is also transitive, then you get bothx < z
andz < x
, which violates antisymmetry. – Capiasx < y < z and not x < z
. – Demarcationa < b
orb < a
must hold for unequala
andb
. – Capias<
to object of type Y", i.e. when the types are different and the types are not both numeric/strings, then the order of the values is defined by the order of just their types. This is even stronger than antisymmetry because it tells you that ifa < b -> forall x, y, type(x)=type(a), type(y) = type(b) -> x < y
. – PeguTypeError
! – Pegu__lt__
to return True and also__gt__
to return True, it would be inconsistent mathematically (because he claims to be both bigger and smaller than 0), but one might call it 'consistent' in another sense because it is consistently wrong - the behaviour is always the same across e.g. different interpreters and platforms. 'Consistent' as 'deterministic', 'predictable'. – Demarcation