Минимальные методы для заказа с использованием утиного набора в Python 3.1

В руководстве сказано:

в общем, __lt__() и __eq__() достаточно, если вам нужны общепринятые значения операторов сравнения

Но я вижу ошибку:

>       assert 2 < three
E       TypeError: unorderable types: int() < IntVar()

когда я запускаю этот тест:

from unittest import TestCase

class IntVar(object):

    def __init__(self, value=None):
        if value is not None: value = int(value)
        self.value = value

    def __int__(self):
        return self.value

    def __lt__(self, other):
        return self.value < other

    def __eq__(self, other):
        return self.value == other

    def __hash__(self):
        return hash(self.value)

class DynamicTest(TestCase):

    def test_lt(self):
        three = IntVar(3)
        assert three < 4
        assert 2 < three
        assert 3 == three

Я удивлен, что когда IntVar() справа, __int__() не вызывается. Что я делаю не так?

Добавление __gt__() исправляет это, но означает, что я не понимаю, каковы минимальные требования для заказа...

Спасибо, Эндрю


person andrew cooke    schedule 07.04.2012    source источник
comment
Если вы посмотрите на богатые документы по методам сравнения это конкретно упоминает это поведение -- There are no swapped-argument versions of these methods (to be used when the left argument does not support the operation but the right argument does); rather, __lt__() and __gt__() are each other’s reflection, __le__() and __ge__() are each other’s reflection, and __eq__() and __ne__() are their own reflection. Arguments to rich comparison methods are never coerced.   -  person agf    schedule 07.04.2012
comment
@agf: ответы должны быть в ответах, а не в комментариях.   -  person Ethan Furman    schedule 07.04.2012
comment
@EthanFurman Документы не помогут вам в конкретном случае, как это делает ответ Свена, и ИМО, которое необходимо для публикации в качестве ответа, а не просто комментария.   -  person agf    schedule 07.04.2012


Ответы (1)


Python 3.x никогда не будет выполнять приведение типов для операторов, поэтому __int__() в этом контексте не используется. Сравнение

a < b

сначала попытается вызвать type(a).__lt__(a, b), и если это вернет NotImplemented, то вызовет type(b).__gt__(b, a).

Цитата из документации говорит о том, что сравнения работают для одного типа, и приведенное выше объяснение показывает, почему этого достаточно для одного типа.

Чтобы ваш тип правильно взаимодействовал с int, вы должны либо реализовать весь оператор сравнения, либо использовать total_ordering декоратор доступен в Python 2.7 или 3.2.

person Sven Marnach    schedule 07.04.2012
comment
Благодарю. совсем забыл про total_ordering. это отлично подойдет. - person andrew cooke; 07.04.2012
comment
total_ordering работает в вашем случае. Однако в двух разных классах, использующих total_ordering, могут возникать ошибки: bugs.python.org/issue10042. - person Lennart Regebro; 08.04.2012