Is 0 > None??

Tim Peters tim.one at home.com
Fri Aug 31 21:22:50 EDT 2001


[Manus Hand]
> Yes, I knew I was opening myself up for nifty-tricking.
>
> And yes, I knew from when the result of "0 < None" changed
> when 1.5.2 came out that it is explicit that its undefined.
>
> So I repeat, I knew I was opening myself up.  Just thought
> I could convince TPTB that maybe it was worth defining.

Actually, at the last second Guido put in a hack to ensure than None
compared less than anything else.  If it *has* to mean something, that's as
good as anything, and seemed better than most.

> If I'm the only one foolish enough to write code that depends
> on the result of 0 < None, well, I will feel especially special.

We can hope <wink>.

> And yes, I knew there was no such thing as sys.minint.  :-)
>
> Someone asked what the affected code was.  Here is
> a simplified rundown.
>
> class Consortium:
>     def __init__(self):
>         self.bids = [None] * 3
>     def bid(self, who, amt):
>         self.bids[who] = min(self.bids[who], amt)
>
> In other words, I was too lazy to type:
>         if self.bids[who] is None: self.bids[who] = amt
>         else: self.bids[who] = min(self.bids[who], amt)
>
> Continuing....
>
>     def __cmp__(self, other):
>         return cmp(self.bids, key.bids)  # None compares "correctly"
>
> The class provides a list of bid amounts, one for each of three ordered
> persons.  These people each contribute money to different consotriums
> to purchase something.
>
> Let's say these people are named Al, Bud, and Carl.  Al is bidder #1
> (any amount he offers to a cpecific consortium's bid goes into the
> [0] element of the bids attribute).  Bud is bidder #2 (his offer goes
> into the [1] element) and Carl is bidder #3 (his offer goes into the [2]
> element).
>
> If two consortiums offer the same total bid, the one that wins is
> the one in which Al offered LESS money.  If Al offered the same amount
> to both winning consortiums (or did not contribute to either of them),
> then the winning bid is the one in which BUD offered LESS money.
> Again, if Bud offered the same amount or did not offer at all, Carl's
> data would determine.  (Okay, I simplified the application too much;
> if Al and Bud's offer amounts don't break the tie, Carl's sure won't;
> trust me, though -- in the real, more complex application, two
> Consotriums are guaranteed to compare unequal).
>
> The thing that was handy was that not offering money to a consortium
> (i.e., "None" for your entry) compared worse than having offered
> a hundred zillion million dollars. (which was worse than having offered
> only niney-nine zillion million dollars, which was worse than having
> offered ... etc., etc., which was worse than the best possible offer,
> which is one single dollar).

And this is "a reason" to make None compare larger than anything else?  What
if you were running an auction instead, and wanted the *high* bid to win
(and so None "should be" less than anything else)?  This is utterly
arbitrary.

> Changing the __cmp__() function was a sad thing to do.  I had
> created the bids list specifically so that list comparison would work.
>
> I could make the value assigned to "bids" in __init__() thus:
>     self.bids = [sys.maxint] * 3
>
> :-(
>
> The thing is, __repr__ was very nice.  It was obvious when someone had
> bid money and when he didn't, because the word "None" showed up.
>
> I know I could continue with "None" in the bids, if I'm really that
> concerned about __repr__(), but that would mean a __cmp__()
> function that is far more complicated than
>     return cmp(self.bids, other.bids)
>
> Well, a bit more complicated -- I could do this:
>     return cmp([x is None and sys.maxint or x for x in self.bids],
>                [x is None and sys.maxint or x for x in self.bids])
>
> Okay, I've wasted enough of your time.

Yes, but I'm not done wasting yours <wink>.  If you want a magical value,
build one explicitly; there's no need to mangle your __cmp__ etc:

class Infinity:
    def __init__(self, name):
        self.reprname = name

    def __cmp__(self, other):
        if isinstance(other, Infinity):
            return 0
        return 1

    def __repr__(self):
        return self.reprname

NoBid = Infinity("no bid")

print min([NoBid] * 3) # prints "no bid"
print min([NoBid] * 2 + [500]) # prints 500

Now you've got a NoBid object that compares greater than anything else
(except for another of its own kind -- season to taste), that displays as

    no bid

when repr()ed (season to taste), and where both behaviors are reliable
because explicitly coded.  If you want to keep it obscure <wink>, replace
the __repr__ guts with

    return not isinstance(other, Infinity)

clean-and-filthy-all-at-the-same-time-ly y'rs  - tinm





More information about the Python-list mailing list