Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Сравнение объектов встроенных типов в Пайтоне

Некоторым ребятам показалось, что в заметке про «goatse operator» в Перле я поругал этот язык. Это не так, можно прочитать заметку от и до, чтобы в этом убедиться. Мне очень нравится Перл, но это язык не для современного продакшна. Давайте я что-нибудь забавное расскажу и о языке, на котором больше всего сейчас программирую — про Пайтон.

В Пайтоне всё что только можно — объект и нет примитивных типов. С объектами можно делать всё что хочется — сравнивать, умножать, производить битовые операции. Чтобы программист мог указать как объекту следует себя вести рядом с каким-то оператором, следует определить некоторые «магические» методы, например, «__cmp__», «__mul__» и какой-нибудь «__xor__».

Где-то внутри какие-то «магические» методы определены и для встроенных типов (которые тоже являются объектами, напоминаю), ведь надо же как-то сравнивать две строки или строку и число:

In [26]: "Это строка".__eq__
Out[26]: <method-wrapper '__eq__' of str object at 0x10136f770>

In [27]: "Это строка".__ne__
Out[27]: <method-wrapper '__ne__' of str object at 0x10139cf70>

Сравнивать между собой можно большинство встроенных типов — список с со словарём, строку с кортежем и так далее. Есть исключения (например, set нельзя сравнить ни с чем, кроме set и frozenset), но их мало. Какой же будет результат сравнения? Давайте попробуем:

In [44]: "">()
Out[44]: False

In [45]: ""<()
Out[45]: True

In [46]: []>()
Out[46]: False

In [47]: []<()
Out[47]: True

In [48]: []<{}
Out[48]: False

In [49]: []>{}
Out[49]: True

Даже пустые объекты разных типов не равны между собой, но какое-то правило определённо есть, не случайным же образом создатели языка выбирали что больше чего. Добавление значений в объекты ситуацию не меняет, не играет роли их число и значение. Я намеренно оставляю в стороне числа (типы int, float и complex) и лишь походя затрагиваю строки (str и unicode), там как там правила немного другие, но это неважно.

In [52]: [1,2,3,4,5,6]<(0,)>[100000]
Out[52]: True

Не знаю где это написано в документации, не искал, но я совершенно случайно, из какой-то книги знаю, что на самом деле сравниваются первые буквы типов. Зная эта правило, легко сформировать длинное сравнение, которое будет истиной:

True < {} < [] < object() < "" < () < u""
# b < d < l < o < s < t < u

Решение мне кажется, мягко говоря, неудачным, но уж какое выбрали. Я не вижу ничего страшного в том, чтобы сравнение встроенных типов всегда выдавало False (попробуйте сравнить между собой два None) или выдавать исключение при попытке их сравнения (кажется в 3-й версии Пайтона так и сделали).

2 комментария
www.doma-vrn.ru 2011

from decimal import Decimal
Decimal(’5’) < 10.0

False

Евгений Степанищев (bolknote.ru) 2011

Комментарий для http://www.doma-vrn.ru:

Это не встроенный тип. Кроме того, это всё численные типы, про которые я писал: «оставляю в стороне числа (типы int, float и complex) и лишь походя затрагиваю строки (str и unicode), там как там правила немного другие, но это неважно».