Alex Riley
Alex Riley

Reputation: 177048

Python statement: sometimes True, sometimes False. Why?

I wanted to get a better understanding of OOP in Python and wrote a bit of code describing (infinite) ordinal arithmetic. I defined a class named Omega() with the usual comparison operators (==, <=, etc.), addition and multiplication.

I thought I'd check whether (as should be true) the first infinite ordinal added to itself was less-than-or-equal-to the first uncountable ordinal. Launching the interactive shell, here's what I found:

    >>> a, b = Omega(), Omega(1)
    >>> (a+a) <= b
    False
    >>> (a+a) <= b
    True
    >>> (a+a) <= b
    False

The same expression produces different truth values.

I continued to test the expression and could not spot any pattern. If I re-interpret the code, I find that repeatedly testing the expression produces a different sequence of True/False values.

What could be causing this behaviour?

If it's relevant, I'm using CPython 2.7.5 on Windows 8.1.

Here's the Python code I ran: http://pastebin.com/XPqMphBw

Upvotes: 3

Views: 695

Answers (2)

Jonathan Eunice
Jonathan Eunice

Reputation: 22483

Like @Padraic Cunningham, I also cannot replicate your problem (under Python 2.7.5 on Mac OS X). It gives me consistent answers.

You would do well to give your objects a comprehensible __repr__ method so that they are easily printed 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)

Printing a would then show Omega(0, 1, 1). A slightly fancier 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 is probably not computing "less than or equal" the way you think it is. You have methods __leq__ and __geq__ defined, but those are not part of the Python data model. You want (and need) __le__ and __ge__ instead. If those are not defined, a combination of __eq__ and __lt__ are called instead. That combination generally has logical equivalency, if you're using a standard algebraic definition of <=, but in this case... It's at least a place to check.

Upvotes: 1

Adriano
Adriano

Reputation: 1733

I believe you overloaded the <= and >= operators incorrectly. Instead of:

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

Upvotes: 6

Related Questions