[Tutor] Beginner's question

eryksun eryksun at gmail.com
Thu Nov 22 20:50:39 CET 2012


On Thu, Nov 22, 2012 at 10:49 AM, Dave Angel <d at davea.name> wrote:
>
>>     x, y, z = 26, 15, 20
>>
>>     largest = None
>>     if x %2:
>>          largest = x
>>     if y % 2:
>>          if y > largest:
>>               largest = y
>>     if z % 2:
>>          if z > largest:
>>               largest = z;
>>
>>    if Largest:
>>          print "largest value is", largest
>>    else:
>>          print "no odd values"
>>
>
> This one first gets into trouble if x is even and y is odd, because if
> tries to compare y with None, which is basically an undefined ordered
> comparison (and illegal in Python3, I believe).  The flag value needs to
> be an int, or at least numeric.

Yes, comparing an int to None raises a TypeError in Python 3, but it
is 'defined' in 2.x, for what it's worth. Since

    NoneType lacks tp_richcompare (__lt__, __gt__, etc)
    NoneType lacks tp_compare (__cmp__)
    int/long lack tp_richcompare for a swapped operation
    int/long tp_compare isn't _PyObject_SlotCompare
    None can't be coerced (__coerce__) to an int/long

the comparison falls through to default_3way_compare, where it's hard coded:

    /* None is smaller than anything */
    if (v == Py_None)
        return -1;
    if (w == Py_None)
        return 1;

http://hg.python.org/cpython/file/70274d53c1dd/Objects/object.c#l750

If you want a warning for this, start the interpreter with the -3
flag. The first time you try to compare None to a number in your code
(except for EQ/NE), you'll get a deprecation warning:

    >>> None < -1
    __main__:1: DeprecationWarning: comparing unequal types not
    supported in 3.x
    True

Also, "smaller than anything" only applies to the default case, after
having exhausted all other avenues. You can make your own type that's
'smaller' than anything, including None:

    import functools

    @functools.total_ordering
    class LT(object):
        def __eq__(self, other):
            return isinstance(other, LT)
        def __lt__(self, other):
            if isinstance(other, LT):
                return False
            return True

    def max_odd(seq, reduce=functools.reduce):
        sentry = LT()
        test = lambda x, y: y if y % 2  and y > x else x
        result = reduce(test, seq, sentry)
        if result == sentry:
            raise ValueError("No odd numbers")
        return result

You can unroll the reduction as a chain of statements as Joel did, if
you have to. Just replace "largest = None" with "largest = sentry =
LT()".


More information about the Tutor mailing list