Python operator: Sometimes True, sometimes False. What for?
I wanted to better understand OOP in Python and wrote some code describing (infinite) ordinal arithmetic. I have defined a named class with the Omega()
usual comparison operators ( ==
, <=
etc.), Addition and Multiplication.
I thought I would check how (as should be true) the first infinite ordinal added to itself was less than or equal to the first uncountable order. Launching an interactive shell, this is what I found:
>>> a, b = Omega(), Omega(1)
>>> (a+a) <= b
False
>>> (a+a) <= b
True
>>> (a+a) <= b
False
The same expression expresses different truth values.
I kept testing the expression and couldn't find any pattern. If I re-interpret the code, I find that repeatedly testing the expression creates a different sequence of True
/ values False
.
What could be the reason for this behavior?
If this is relevant, I am using CPython 2.7.5 on Windows 8.1.
Here's the Python code I ran: http://pastebin.com/XPqMphBw
source to share
I believe that you overloaded the <=
and operators incorrectly >=
. Instead:
def __leq__(self, other):
# ...
def __geq__(self, other):
use this instead:
def __le__(self, other):
# ...
def __ge__(self, other):
After making these changes and running this in Python 3.4.1, I get:
>>> a, b = Omega(), Omega(1)
>>> (a+a) <= b
True
>>> (a+a) <= b
True
>>> (a+a) <= b
True
source to share
Like @Padraic Cunningham, I also cannot replicate your problem (under Python 2.7.5 on Mac OS X). This gives me consistent answers.
You might find it helpful to provide the objects with an acceptable method __repr__
so that they can be easily printed out for debugging purposes. For example:
def __repr__(self):
innards = ", ".join(str(v) for v in [self.index, self.power, self.copies])
return "{0}({1})".format(self.__class__.__name__, innards)
The print a
then shows Omega(0, 1, 1)
. A slightly more favorable version might be:
def __repr__(self):
innards = "index={index}, power={power}, copies={copies}".format(**self.__dict__)
return "{0}({1})".format(self.__class__.__name__, innards)
I also note that your code probably doesn't compute "less than or equal to" as you think. You have established methods __leq__
and __geq__
, but they are not part of the Python data model . Instead, you want (and need) __le__
and __ge__
. If they are not defined, the combination of __eq__
and is called instead __lt__
. This combination usually has logical equivalence if you use the standard algebraic definition <=
, but in this case ... This is at least a place to check.
source to share