2015-04-22 3 views
0

У меня есть вопрос относительно поведения python '> ='.python> = оператор на классах

У меня есть старый класс TimeStamp, который содержит (час, минута) кортеж и предлагает некоторые методы, такие как __eq__, __gt__, __lt__.

Я рефакторинг, чтобы он также учитывал день и секунду, и хранить данные в виде полных секунд. Здесь я внедрил __eq__, __gt__, __lt__.

Однако далее в коде я использую> = оператор для этого класса и в то время как старая версия класса работает должным образом, с новым я получаю

TypeError: unorderable types: TimeStamp() >= TimeStamp() error. 

код ниже:

class TimeStamp(tuple): # OLD, WORKING VERSION 
    """TimeStamp, hh:mm tuple supporting comparison and addition""" 
    __slots__ =() 
    def __new__(cls, *args): 
     if len(args) == 1: # tuple entrance 
      hour, minute = args[0] 
     elif len(args) == 2: # hour, minute entrance 
      hour, minute = args[0], args[1] 
     else: 
      raise TypeError('wrong input to TimeStamp') 
     div, minute = divmod(minute, 60) 
     hour += div 
     _, hour = divmod(hour, 24) 
     return tuple.__new__(cls, (hour, minute)) 

    @property 
    def abs_min(self): 
     return self.hour * 60 + self.minute 

    def __gt__(self, rhs): 
     return self.abs_min > rhs.abs_min 

    def __lt__(self, rhs): 
     return self.abs_min < rhs.abs_min 

    def __eq__(self, rhs): 
     return self.abs_min == rhs.abs_min 

Новая версия:

class TimeStamp: 
    def __init__(self, *args): 
     for argument in args: 
      if not isinstance(argument, int): 
       raise TypeError("Can only build TimeStamp from ints, not: " + str(argument)) 

     if len(args) == 1: # init by abs 
      self.abs = args[0] # put the ELEMENT, not the tuple itself 
     elif len(args) == 2: # init by hour:minute 
      hour, minute = args 
      self.abs = hour * 60 * 60 + minute * 60 
     elif len(args) == 4: #init by day:hour:minute:second 
      day, hour, minute, second = args 
      self.abs = day * 24 * 60 * 60 + hour * 60 * 60 + minute * 60 + second 
     else: 
      raise TypeError("wrong data for TimeStamp: " + str(args)) 

    def __eq__(self, other): 
     if isinstance(other, TimeStamp): 
      return self.abs == other.abs 
     else: 
      raise TypeError("wrong argument for comparison: " + str(other)) 

    def __gt__(self, other): 
     if isinstance(other, TimeStamp): 
      return self.abs > other.abs 
     else: 
      raise TypeError("wrong argument for comparison: " + str(other)) 

    def __lt__(self, other): 
     if isinstance(other, TimeStamp): 
      return self.abs < other.abs 
     else: 
      raise TypeError("wrong argument for comparison: " + str(other)) 

Теперь для части сравнения:

if args[1] >= self.start: 
>>TypeError: unorderable types: TimeStamp() >= TimeStamp() 

Я нашел два исправления: первое, чтобы заменить мою сравнительную линию с

if args[1] > self.start or args[1] == self.start: 

или альтернативы, чтобы добавить

def __ge__(self, other): 
    if isinstance(other, TimeStamp): 
     return self.abs >= other.abs 
    else: 
     raise TypeError("wrong argument for comparison: " + str(other)) 

к моему новому классу. Однако старый не работал ни с одним из этих исправлений. Мне кажется, что Python прекратил вычитать, что ((a> b) или (a == b)) подразумевает (a> = b). Но зачем это работало раньше? Имеет ли это что-то общее со мной, подклассифицируя кортеж?

PS. не бойтесь моего кода __init__, который я включил для полноты. Это должно быть от перегрузки, как, но я мог бы делать это в не вещий образом (по-прежнему обучения)

+0

Что произойдет, если вы наследуете TimeStamp от 'object'? – mgilson

+0

Вы также можете проверить 'functools.total_ordering', чтобы вы не могли самостоятельно писать все богатые методы сравнения. – mgilson

+0

Заключительный комментарий. Вместо того, чтобы поднимать 'TypeError', вы должны возвращать' NotImplemented'. Нет причин говорить другим классам, что они не могут сравниться с 'TimeStamp', если они знают, как это сделать.(Он также устраняет фанковые ошибки, такие как 'time_stamp> my_class', поднимающий TypeError, но' my_class <= time_stamp' работает просто отлично) – mgilson

ответ

2

старый один работал, потому что он унаследовал от tuple и tuple обеспечивает __ge__. Ваша новая версия не наследуется от tuple, поэтому у нее нет метода __ge__.

Даже в старой версии, ваши __gt__ и __lt__ методы никогда не вызывается при использовании >= (как вы можете проверить, поставив print внутри этих методов). Вместо этого вызывается базовый tuple.__ge__. Однако, для вашего случая, эффект тот же, поэтому вы не заметили. То есть, учитывая, что число «минут» всегда меньше 60, сравнение (hours, minutes) кортежей обычным способом эквивалентно сравнению 60*hours + minutes. Поэтому я не думаю, что вам действительно нужно определить методы сравнения вообще, если вы наследуете от кортежа.

+1

Итак, чтобы уточнить: Python на самом деле не делает автоматического предположения, что (a> b) || (a == b) эквивалентно (a> = b) ? Я подозревал это, но docs [link] (https://docs.python.org/3.1/library/stdtypes.html) говорит Экземпляры класса не могут быть заказаны в отношении других экземпляров того же класса , или другие типы объектов, если только класс не определяет достаточно методов __lt __(), __le __(), __gt __() и __ge __() (в общем случае __lt __() и __eq __() достаточны, если вы хотите, чтобы обычные значения операторов сравнения). , что означало бы, что lt и eq должно быть достаточно – Jatentaki

+0

Это правильно; Python не делает этого предположения. См. [Документация] (https://docs.python.org/2/reference/datamodel.html#object.__ge__), в которой говорится: «Между операторами сравнения нет подразумеваемых отношений». В документации, на которую вы ссылаетесь, «можно заказать» означает «вы можете придумать способ их заказа»; это не означает, что «Python придумает способ заказать их для вас». Если вы пишете '> =', вызывается '__ge__'. Если вы только определили '__gt__' и' __eq__', вы * можете * упорядочить объекты, но вы должны сделать это явно, используя '>' и '==' отдельно. – BrenBarn

+0

Хорошо, спасибо большое. Это была моя проблема – Jatentaki

Смежные вопросы