Есть ли реализация Python2, где порядок является транзитивным?

Существует ли какая-либо существующая реализация Python2, где порядок является транзитивным? То есть там, где невозможно увидеть это поведение без создания пользовательских типов:

>>> x < y < z < x
True

CPython не является транзитивным из-за этого контрпример

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

Однако это упорядочение в CPython задокументировано только как деталь реализации.

2 ответа

Решение

Каждая основная реализация Python так или иначе дает сбой, за исключением Skulpt, но, возможно, это неполная реализация.

CPython (и варианты), PyPy и Jython:

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

IronPython:

IronPython внутренне сравнивает.NET Object.GetHashCode() хэши разнородных объектов, так что вы можете разбить его, злоупотребив специальной обработкой int а также float сравнения и тот факт, что внутреннее представление хеш float('+inf') меньше чем хеш [] (Я не уверен, насколько это стабильно, поэтому он может не работать на каждой установке IronPython):

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

CLPython

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

Skulpt

Если вы считаете Skulpt полной реализацией Python 2 (он не может сравнивать словари и несколько других неудобных типов, и не имеет unicode типа), он действительно работает, копируя правила CPython для сравнения и удобно опуская unicode тип:

# 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

Для CPython 2 вы бы на самом деле [t]uple < [u]nicode, но потому что unicode а также str Сравнения обрабатываются как особый случай, вы теряете транзитивность. Хотя маловероятно, что Python 2 получит патч для исправления этой "ошибки", я думаю, что вы можете обеспечить транзитивность, просто явно изменив порядок с:

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

Для того, чтобы:

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

Таким образом, особый случай str в unicode Сравнения ничего не нарушают.

Некоторые сравнения объявлены как не указанные в Python 2.7:

Наиболее важные общие правила сравнений приведены в главе 5 " Справочник по языку Python". Выражения / 5.9. Сравнения.

Первые правила хорошо известны для сравнения числовых типов (bool, int, long, float), строк (str, unicode), кортежей и списков. Последние два правила объявляют то, что не указано:

  • Сопоставления (словари) сравниваются равными тогда и только тогда, когда их отсортированные списки (ключ, значение) сравниваются равными. [5] Результаты, отличные от равенства, решаются последовательно, но не определяются иначе. [6]
  • Большинство других объектов встроенных типов сравниваются неравно, если они не являются тем же объектом; выбор, считать ли один объект меньшим или большим другого, делается произвольно, но последовательно в течение одного выполнения программы.

Многие конкретные правила содержатся в главе " Сравнение" в "Стандартной библиотеке Python" / " Встроенные типы", ссылка на которую приведена выше в вопросе, и в документах о конкретных типах, таких как сложный, десятичный или дробный.

Сравнение порядка не поддерживается для типа complex и должно вызывать TypeError. Десятичный тип сравнивается по значению. Он совместим с числами. Номер начиная с Python 2.7. фракции. Фракция также сравнивается по значению.


Мое размышление: если отношение сравнения может быть произвольным и не воспроизводимым при двух выполнениях программы на одном компьютере, то о транзитивности говорить бесполезно. Все вышеперечисленные случаи, когда порядок явно не указан в Python 2, должны вызывать TypeError в Python 3.

Транзитивность или упорядоченность встроенных типов, как известно, нарушена в Python 2.7 только между типами, в которых реализована эквивалентность значений различных встроенных типов, но они не реализованы эквивалентно другим типам.

Пример: нарушенная транзитивность в IronPython (вдохновлена ​​комментариями Блендера и упрощена):

>>> assert long(0) < 1.0 < [] < long(0)  # 0 < 1; 'float' < 'list' < 'long'

Даже эквивалентность (==), который выглядит проще для принятия решения, также не всегда транзитивен. Это нарушает транзитивность оператора (<=). Смотрите примеры в комментариях. (Спасибо за исправление) (Эквивалентность не идентичность. a is b подразумевает a == b, но не наоборот.)

В примерах используется множество простых пользовательских классов с именами, состоящими из одной буквы, заглавной или строчной:

class A(object): pass

class a(object): pass
...

class z(object): pass

Наблюдение - Числа

Все числовые типы имеют много естественно эквивалентных значений в CPython и IronPython (и, вероятно, во всех других реализациях в соответствии с документами)

>>>  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))

Числовые типы упорядочены раньше всех других типов в CPython:

>>> assert 0 < 10**1000 < float('inf') < A() < Z() < a()

Числовые типы распределены между другими типами в 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

Струны и т. Д.

str, bytearray и unicode имеют эквивалентные значения

>>> assert bytearray('ab') == 'ab' == u'ab'

Ничего особенного в упорядочении по другим типам не используется в CPython,

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

В IronPython: тип unicode ведет себя как str, Это не странно, потому что строки реализованы в.NET, как Unicode, и то же самое в IronPython.

 >>> assert s() < u'ab' < t()           # unicode in Iron Python like str
 >>> unicode
 <type 'str'>
Другие вопросы по тегам