Is there any Python2 implementation where the ordering is transitive?

Is there any existing Python2 implementation where the ordering is transitive ? That is, when it is impossible to see this behavior without creating custom types:

>>> x < y < z < x True 

CPython is not transitive due to this counterexample

 x = 'b' y = () z = u'ab' 

However, this order is documented in CPython as an implementation detail.

+7
python sorting
source share
2 answers

Each major Python implementation does not execute in any way other than Skulpt, but it may be an incomplete implementation.

CPython (and variants), PyPy and Jython :

 >>> 'b' < () < u'ab' < 'b' True 

IronPython

IronPython internally compares the hashes of the .NET Object.GetHashCode() dissimilar objects, so you can break it by misusing the special handling of int and float comparisons and the internal hash representation of float('+inf') smaller than the hash [] (I don't sure how stable this is, so it may not work with every IronPython installation):

 >>> 2**200 < float('+inf') < [] < 2**200 True 

CLPython

 >>> {1: 3} < {1: 4} < {1: 3} 1 >>> {1: 3} < {1: 3} 0 

Skulpt

If you consider Skulpt as a full implementation of Python 2 (it cannot compare dictionaries and several other inconvenient types, and does not have a unicode type), it really works by copying CPython rules for comparison and conveniently leaving the unicode type:

 # 1. None is less than anything # 2. Sequence types are greater than numeric types # 3. [d]ict < [l]ist < [s]tring < [t]uple >>> None < 0 < {} < [] < '' < () True 

For CPython 2, you really have [t]uple < [u]nicode , but since unicode and str comparisons are treated as a special case, you lose transitivity. Although it is unlikely that Python 2 will receive a fix to fix this “error,” I think you can provide transitivity by simply changing the order:

 [d]ict < [l]ist < [s]tring < [t]uple < [u]nicode 

To:

 [u]nicode < [d]ict < [l]ist < [s]tring < [t]uple 

Thus, the special case of str - unicode comparison does not violate anything.

+2
source share

Some comparisons are declared as not specified in Python 2.7:

The most important general rules for comparison are given in the Python Language Reference chapter 5. Expressions /5.9 Comparisons .

The first rules are numerical types (bool, int, long, float), strings (str, unicode), tuples and lists that are well known for comparison. The last two rules declare what is not specified:

  • Mappings (dictionaries) are compared equal if and only if their sorted (key, values) lists are compared equal. [5] Results other than equality are resolved sequentially, but are not defined otherwise . [6]
  • Most other objects of built-in types are compared unevenly if they are not the same object; the choice of whether one object is considered smaller or larger than another is made arbitrarily , but sequentially within the framework of one program execution .

Many special rules are contained in the Comparison chapter in the Python standard library / built-in views mentioned above in the question, and in documents about specific types, such as complex, decimal, or fractional.

Order comparisons are not supported for the complex type, and it should raise a TypeError. The decimal type is compared by value. It is compatible with numbers. Number since Python 2.7. fractions. The fraction is also compared by value.


My reflection: if the comparison relation can be arbitrary and cannot be reproduced in two executions of the program on one computer, then it is not useful to talk about transitivity. All of the above cases where the order is not explicitly specified in Python 2 should raise a TypeError in Python 3.

The transitivity or ordering of built-in types is known in Python 2.7, only between types where the values ​​of different built-in types are equivalent, but they are not implemented equivalently 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 equivalence ( == ), which looks simpler, is also not always transitive. This violates the transitivity of the operator ( <= ). See examples in the comments. (Thanks for the correction) (Equivalence is not an identity. a is b implies a == b , but not vice versa).

The examples use many trivial user classes with single-letter or lowercase names:

 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 as per the 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 shared among 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' 

CPython in CPython doesn't use anything special when ordering other types,

 >>> assert b() < bytearray('ab') < c() # bytearray >>> assert s() < 'ab' < t() # str >>> assert u() < u'ab' < v() # unicode in CPython 

In IronPython: the unicode type behaves like str . This is not strange, because strings are implemented in .NET as unicode, and the same in IronPython.

  >>> assert s() < u'ab' < t() # unicode in Iron Python like str >>> unicode <type 'str'> 
0
source share

All Articles