28
Python 2.7.2 (default, Jun 12 2011, 14:24:46) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> None > 0
False
>>> None == 0
False
>>> None < 0
True
  • Is comparing None using arithmetic operators well defined for built-in types (integers in this case)?
  • Is the difference between the first two and the third comparison part of language specification (Python's specification - you must be kidding :)) or is it CPython's implementation detail?
Piotr Dobrogost
  • 41,292
  • 40
  • 236
  • 366
  • 4
    `==` and `!=` are usually safe, but you are supposed to use `is None` and `is not None` for singletons such as `None` as per [PEP-8](http://www.python.org/dev/peps/pep-0008/) – ThiefMaster Jan 22 '12 at 12:27
  • 2
    @ThiefMaster The whole point of the question is what does *safe* mean here. I'm well aware one should use `is` to compare with `None` but question is specific and does not ask about which operator should be used. – Piotr Dobrogost Jan 22 '12 at 12:32
  • http://bugs.python.org/issue1673405 – wim Jan 22 '12 at 14:01
  • 1
    Duplicate: [Is everything greater than None?](https://stackoverflow.com/questions/2214194/is-everything-greater-than-none) – Georgy Nov 11 '19 at 09:27

2 Answers2

30

The only meaningful comparison you can really use with None is if obj is None: (or if obj is not None:).

Comparison between different types has been removed from Python 3 for good reasons - they were a common source of errors and lead to confusion. For example

>>> "3" < 4
False

In Python 3, you get a TypeError when comparing values of different types like str vs. int or anything vs. None.

>>> None < 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: NoneType() < int()

(I mean "comparing" in the sense of trying to determine which of two values is larger/smaller. Comparison for equality is OK - it will always return False if two object are of different types.)

I haven't found a reference in the docs for this, but in Learning Python, 4th edition, Mark Lutz writes on page 204:

[...] Comparisons of differently typed objects (e.g., a string and a list) work — the language defines a fixed ordering among different types, which is deterministic, if not aesthetically pleasing. That is, the ordering is based on the names of the types involved: all integers are less than all strings, for example, because "int" is less than "str".

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • 3
    What is the technical reason why `None < 0` is true? – wim Jan 22 '12 at 13:48
  • 6
    @wim: `None` is the "lowest type" in Python 2, so `None` is always lower than any `int` which is always lower than any `str` etc. – Tim Pietzcker Jan 22 '12 at 14:23
  • @PiotrDobrogost: Don't know, but I've added a quote from Mark Lutz's book "Learning Python" (highly recommended). – Tim Pietzcker Jan 22 '12 at 14:30
  • *(...) the language defines a fixed ordering among different types (...) That is, the ordering is based on the names of the types involved* is in contradiction with *(...) objects of different types will compare according to an ordering on their types (an implementation dependent, (...)* cited in wim's answer. Where's the truth? – Piotr Dobrogost Jan 22 '12 at 17:04
  • It's been a while since I've used python, so I'm probably missing something really obvious. What do you mean by "comparison for identity"? I thought that we used "is" for that purpose. Please do let me know. – batbrat Jan 22 '12 at 18:11
  • 1
    @batbrat: Sorry, I meant equality. Thanks for spotting this error. Fixed. – Tim Pietzcker Jan 22 '12 at 18:17
  • It makes sense now. Thanks for fixing it :) – batbrat Jan 22 '12 at 18:24
6

Some interesting quotes from http://bytes.com/topic/python/answers/801701-why-none-0-a

In early Python, the decision was made that the comparison of any two objects was legal and would return a consistent result. So objects of different types will compare according to an ordering on their types (an implementation dependent, unspecified, but consistent ordering), and objects of the same type will be compared according to rules that make sense for that type.

Other implementations have the right to compare an integer and None differently, but on a specific implementation, the result will not change.

Python 3 will raise an exception on such comparisons.

and

The problem is the typical one; Python did not originally have a Boolean type, and the retrofit resulted in weird semantics. C has the same issue.

wim
  • 338,267
  • 99
  • 616
  • 750
  • 1
    This is really sick. Another reason to avoid Python 3 as long as possible. So you can't sort a list of heterogenous objects as of now... `>>> sorted([2, 1.5, 2.5]) [1.5, 2, 2.5] >>> sorted([2, 1.5, 2.5, 'bla', '2', '2.5', None]) Traceback (most recent call last): File "", line 1, in TypeError: unorderable types: str() < int()`. – Tomasz Gandor May 12 '14 at 14:06
  • 14
    I would argue that as a reason to _prefer_ python 3.. What is the expected result from `sorted([2, 1.5, 2.5, 'bla', '2', '2.5', None])` ? – moveaway00 Sep 30 '15 at 14:10
  • @TomaszGandor Reading your comment in 2021 – jtlz2 Mar 13 '21 at 20:30
  • 1
    @moveaway00 - `[None, 1.5, 2, 2.5, '2', '2.5', 'bla']`, and without checking I would at least say that `None` should come first (and numbers before strings? this also makes some sense). @jtlz2 - yes, much has changed since then. One such thing was the good old Python 3.6. – Tomasz Gandor Mar 13 '21 at 21:34