True
    >>> None < -float('inf')
    True
    >>> None < 'foobar'
    True
    >>> 'foobar' > -1
    True
    >>> 'foobar' > 42
    True
    >>> tuple >= (lambda x: x)
    True
    >>> type > Ellipsis
    True
    

Oh… of course. It’s Python2 that we use on the project (doh).

You see, Python2 is perfectly happy to compare objects of different types,
even when that does not make much sense. Peeking into the ` CPython ` source
code reveals that ` None ` is [ smaller than anything
](https://github.com/python/cpython/blob/2.7/Objects/object.c#L779-L783) :

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

Different types are [ ordered by name
](https://github.com/python/cpython/blob/2.7/Objects/object.c#L785) , with
number types being smaller than other types  3  .

Now that we know this, the bug from the beginning makes perfect sense. It was
just a coincidence that ` high_value ` could be set on an instance, because
the validator’s check for an error ( ` value ` <= ` self.value_low ` ) would
never return ` True ` when ` self.value_low ` is ` None ` , because the latter
is smaller than everything.

In the end the issue was, fortunately, quickly discovered, and fixing it was
straightforward. We just needed to add an extra check:

    
    
    if (
        key == 'value_low' and
        self.value_high is not None and  # <-- THIS
        value >= self.value_high):
        ...
    # and the same for the other if...
    

_And the application worked correctly and happily ever after…_

* * *

  1. That’s probably because when creating a new instance of the model, SQLAlchemy loops over the ` kwargs ` dict somewhere down the rabbit hole, but the order of the dictionary keys is arbitrary.  ↩ 
  2. Python2 only. In Python3 we would get ` TypeError: unorderable types ` .  ↩ 
  3. Provided that types do not define their own custom rich comparison methods, of course.  ↩ 

###  Share this:

  * [ Twitter  ](https://blog.peterlamut.com/2017/09/28/comparing-objects-of-different-types-in-python-2/?share=twitter "Click to share on Twitter")
  * [ Facebook  ](https://blog.peterlamut.com/2017/09/28/comparing-objects-of-different-types-in-python-2/?share=facebook "Click to share on Facebook")
  * 

Like  Loading...

![](https://1.gravatar.com/avatar/47889a61e55c396e2ea18b0de05fa8a63f36cf32eddcf552613be0ebca37fb83?s=49&d=identicon&r=G)
Author  [ Peter Lamut ](https://blog.peterlamut.com/author/peterlamut/) Posted
on  [ September 28, 2017  ](https://blog.peterlamut.com/2017/09/28/comparing-
objects-of-different-types-in-python-2/) Tags  [ CPython internals
](https://blog.peterlamut.com/tag/cpython-internals/) , [ Python
](https://blog.peterlamut.com/tag/python/) , [ SQLAlchemy
](https://blog.peterlamut.com/tag/sqlalchemy/) [ Leave a comment  on Comparing
objects of different types in Python 2
](https://blog.peterlamut.com/2017/09/28/comparing-objects-of-different-types-
in-python-2/#respond)

##  About the Author

![](https://1.gravatar.com/avatar/47889a61e55c396e2ea18b0de05fa8a63f36cf32eddcf552613be0ebca37fb83?s=96&d=identicon&r=G)  
I am an experienced software engineer, primarily using Python and JavaScript
in my day-to-day work, putting a strong emphasis on writing clean and
maintainable code.

I use Linux, like to crack jokes, and enjoy attending developer meetups and
conferences like EuroPython.

I do not own any pets or hair care products.

Search for:  Search

##  Tags

  * [ Attribute lookup ](https://blog.peterlamut.com/tag/attribute-lookup/)
  * [ ChainMap ](https://blog.peterlamut.com/tag/chainmap/)
  * [ Classmethod ](https://blog.peterlamut.com/tag/classmethod/)
  * [ CPython internals ](https://blog.peterlamut.com/tag/cpython-internals/)
  * [ Debugging ](https://blog.peterlamut.com/tag/debugging/)
  * [ Decorators ](https://blog.peterlamut.com/tag/decorators/)
  * [ Descriptors ](https://blog.peterlamut.com/tag/descriptors/)
  * [ Dicti