Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing dates in python, == works but <= produces error

I'm trying to compare two dates. This code works:

import datetime

todays_date = datetime.date.today()

date1 = datetime.date(2006, 3, 15)
date2 = datetime.date(2009, 4, 30)

print(date1 != date2)
print(date1 == 0)

It produces:

True
False

Those code does not work and I don't know why:

import datetime

todays_date = datetime.date.today()

date1 = datetime.date(2006, 3, 15)
date2 = datetime.date(2009, 4, 30)

print(date1 != date2)
print(date1 >= 0)

It produces this error:

File 'datetime.py', Line 363: AttributeError: 'int' object has no attribute '__name__'

Note that all I changed was == to >=, why does equality comparison results in True or False, while greater than comparaison results in an error?

I would appreciate any help!

like image 296
Jarod Jacobs Avatar asked Jan 03 '18 04:01

Jarod Jacobs


People also ask

How do I compare two dates that are equal in Python?

You can use equal to comparison operator = to check if one datetime object is has same value as other. In the following program, we initialize two datetime objects, and then check if both datetime objects have same date and time.

How do I check if one date is greater than another in Python?

Use datetime. date() to compare two dates date objects representing the dates of year , month , and day . Use the built-in comparison operators (e.g. < , > , == ) to compare them.

How do pandas compare dates?

Comparison between pandas timestamp objects is carried out using simple comparison operators: >, <,==,< = , >=. The difference can be calculated using a simple '–' operator.


1 Answers

TL;DR

It's because of how the comparison methods are defined.


Reason why `==` is comparable while `>=` isn't between `time` objects and type `int`:

Here's a copy of the source code for the time object:

def __eq__(self, other):
    if isinstance(other, time):
        return self._cmp(other, allow_mixed=True) == 0
    else:
        return False

def __ge__(self, other):
    if isinstance(other, time):
        return self._cmp(other) >= 0
    else:
        _cmperror(self, other)

__eq__ returns False when it's not another time instance, while __ge__ calls _cmperror, which is defined as followed:

def _cmperror(x, y):
    raise TypeError("can't compare '%s' to '%s'" % (
                    type(x).__name__, type(y).__name__))

Very Important Edit

Although this answer already got some positive scores, but I have miss read your question, you used date objects, not time objects.

Reason why `==` is comparable while `>=` isn't between `date` objects and type `int`:

First of all, date objects, unlike time objects, they are implemented the same for __eq__ and __ge__. Both of them actually returns NotImplemented, therefore there's nothing special about the date object's methods:

def __eq__(self, other):
    if isinstance(other, date):
        return self._cmp(other) == 0
    return NotImplemented

def __ge__(self, other):
    if isinstance(other, date):
        return self._cmp(other) >= 0
    return NotImplemented

What is different, however, is int's __eq__ comparison's to the other methods. int returns False when an object has a none-comparable type for __eq__ and NotImplemented for __ge__.

The NotImplemented returned by date will result in a fallback on int's methods. Since int is always equality comparable, date == 0 does not result in an error.

Here is an example:

class LikeDate:
    def __eq__(self, other):
         if isinstance(other, LikeDate):
             return True
         else:
              return NotImplemented

    def __ge__(self, other):
         if isinstance(other, LikeDate):
             return True
         else:
              return NotImplemented

class LikeInt:
    def __eq__(self, other):
         if isinstance(other, LikeInt):
             return True
         else:
             return False

    def __ge__(self, other):
         if isinstance(other, LikeInt):
             return True
         else:
              return NotImplemented

a = LikeDate()
b = LikeInt()
print(a == b) # False
print(a == 0) # False, because int provides an __eq__ method that returns False
print(a >= 0) # Error, because nether LikeDate nor int provides a definite comparison for __ge__
print(a >= b) # Error, because neither objects provide a comparable __ge__

You can run this example here.


If you do not know what return NotImplemented is, here's a short explanation and a quote from the doc:

When a binary [ ( __eq__, __ge__ ...) ] (or in-place) method returns NotImplemented the interpreter will try the reflected operation on the other type (or some other fallback, depending on the operator). If all attempts return NotImplemented, the interpreter will raise an appropriate exception. Incorrectly returning NotImplemented will result in a misleading error message or the NotImplemented value being returned to Python code.

When NotImplemented is returned from a binary method, it refers that the binary method isn't able to compare itself with the targets' type. The result of the binary method will depend on the other objects' binary method. If both object returns NotImplemented an error is raised.

like image 194
Taku Avatar answered Sep 23 '22 18:09

Taku