1

Why does the following happen with Python's lambdas (in both Python 2 and 3)?

>>> zero = lambda n: n is 0
>>> zero(0)
True
>>> zero = lambda n: n is 0.0
>>> zero(0.0)
False
user7501761
  • 91
  • 1
  • 3
  • 2
    this does not have to do with `lambda`s. This has to do with [floating point arithmetic](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) and integer caching (`256` is the last integer that returns `True`!) – Ma0 Mar 23 '18 at 10:50
  • @Ev.Kounis I don't think this relates to floating point arithmetic, it's simply float caching vs integer caching isn't it? – Chris_Rands Mar 23 '18 at 10:56
  • 2
    Possible duplicate of ['is' operator behaves unexpectedly with floats](https://stackoverflow.com/questions/38834770/is-operator-behaves-unexpectedly-with-floats) – Chris_Rands Mar 23 '18 at 11:01
  • To be clear, floats are not cached apparently – Chris_Rands Mar 23 '18 at 11:05
  • 1
    There's almost _never_ an excuse for comparing numbers using `is` instead of `==`. Don't do it, and then you won't see these sorts of surprises. It's an interesting academic exercise to explain what's going on here, but from the point of view of practical programming the question should just never come up. – Mark Dickinson Mar 23 '18 at 12:02

1 Answers1

2

The most common Python implementation store a number of small integers as "constant" or "permanent" objects in a pre-allocated array: see the documentation. So, these numbers can be recongized as identical objects using the is operator. This is not done for floats.

If you were to compare the numbers using the equality operator ==, you'd get identical behaviour for ints as well as floats.

Note that 0 is an integer, and 0.0 is a float.

If you were to use a larger integer instead of 0 (for example, changing the lambda to test for n is 5000, and also plugging 5000 into the function), it would return False again, because the two 5000 numbers would be different objects internally.


Some examples for clarity:

>>> zero = lambda n: n is 0
>>> zero(0)
True

is returns True here because both instances of 0 are literally the same object internally (which is what is checks for).

>>> zero = lambda n: n == 0
>>> zero(0)
True

== returns True this time because the two numbers are equal, not necessarily because they are identical objects internally.

>>> zero = lambda n: n is 5000
>>> zero(5000)
False

This returns False because 5000 is too big a number, it no longer fits in the range of numbers that get pre-allocated internally.

>>> zero = lambda n: n is 0.0
>>> zero(0.0)
False

This returns False again because 0.0 is a float, and for floats there isn't any pre-allocating internally like there is for a limited range of integers, so this is actually exactly the same case as above.

>>> zero = lambda n: n == 0.0
>>> zero(0.0)
True

Using == instead of is results in comparing the numbers again instead of internal objects, so now we get True.

Dennis Soemers
  • 8,090
  • 2
  • 32
  • 55