4

I'm in Python 3.6.5 and I ran across a strange phenomenon: float('50.0') is not the same as float(50.0), though they are equal to each other.

I ran some code to find the difference. Other than python saying that they aren't the same, I can't find a difference. I'm baffled. I'd love it if someone could explain what is happening here.

Here are my tests:

if float('50.0') is float(50.0):
    print("float('50.0') is float(50.0)")
else:
    print("float('50.0') is not float(50.0)")

if float('50.0') == float(50.0):
    print("float('50.0') == float(50.0)")
else:
    print("float('50.0') != float(50.0)")

if float('50.0') is 50.0:
    print("float('50.0') is 50.0")
else:
    print("float('50.0') is not 50.0")

if float(50.0) is 50.0:
    print('float(50.0) is 50.0')
else:
    print('float(50.0) is not 50.0')

if float(50.0) is float(50.0):
    print('float(50.0) is float(50.0)')
else:
    print('float(50.0) is not float(50.0)')

xstr_float = float('50.0')
norm_float = float(50.0)
print ('xstr_float: {0:.100f}'.format(xstr_float))
print ('xstr_float is of type:{}'.format(type(xstr_float)))
print ('norm_float: {0:.100f}'.format(norm_float))
print ('norm_float is of type:{}'.format(type(norm_float)))

and my results:

float('50.0') is not float(50.0)
float('50.0') == float(50.0)
float('50.0') is not 50.0
float(50.0) is 50.0
float(50.0) is float(50.0)
xstr_float: 50.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
xstr_float is of type:<class 'float'>
norm_float: 50.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
norm_float is of type:<class 'float'>

Based on some discussion in the comments I've tried the following, getting results that don't answer the question:

x = float(50.0)
y = float(50.0)
if x is y:
    print('x is y')
else:
    print('x is not y')

x=12345
y=12345
if x is y:
    print('x is y')
else:
    print('x is not y')

results in:

x is y
x is y

UPDATE: I've marked an answer that is correct, and based on a comment on that answer I want to show other people who might be confused what I was missing:

When python creates an object it is assigned an ID. is returns true when comparing two objects returns the same ID. Sometimes python will cache and reuse an object. So in the case of x is y we can see that an object is given and reused because the ID is the same. We also see that the ID changes between python sessions:

x=12345
y=12345
if x is y:
    print('x is y')
else:
    print('x is not y')
print('x_id: {}'.format(id(x)))
print('y_id: {}'.format(id(y)))

results in

x is y
x_id: 2476500365040
y_id: 2476500365040

and on the next run it results in

x is y
x_id: 2234418638576
y_id: 2234418638576

If for any reason the same object couldn't be reused to represent x and y then x is y would return false.

jlsecrest
  • 537
  • 1
  • 5
  • 15
  • 3
    Don't compare values with `is`, use `==`. – Daniel Roseman Jun 21 '18 at 08:55
  • @DanielRoseman it's obvious he is comparing value vs identity which is why both `is` and `==` are used – Morten Jensen Jun 21 '18 at 08:56
  • 1
    But why would he expect different objects to have the same identity? – Daniel Roseman Jun 21 '18 at 08:56
  • Observe: `x=12345; y=12345; (x is y) == False` This has nothing to do with how the float is made. – L3viathan Jun 21 '18 at 08:59
  • @DanielRoseman I'm noticing that two different float objects can either be compared to be identical, or not identical and I'm trying to understand what the difference is. (e.g. `float('50.0') is not 50.0` vs `float(50.0) is 50.0`.) – jlsecrest Jun 21 '18 at 09:02
  • @L3viathan I can't reproduce your results: `x=12345; y=12345; if x is y: print('x is y')` results in `x is y` – jlsecrest Jun 21 '18 at 09:11
  • @jlsecrest Define them in seperate lines, not actually seperated by semicola; in a REPL – L3viathan Jun 21 '18 at 09:13
  • 1
    So to make this perfectly clear, you understand the difference between `==` and `is` and you're asking why CPython sometimes re-uses the same float instance and sometimes not? – Aran-Fey Jun 21 '18 at 09:13
  • @Aran-Fey I did understand that `is` and `==` were different but I wasn't quite clear on all the details. I did not understand enough of the mechanics of python to consider that a python object might be cached or reused. I've accepted an answer that helped me understand the difference more clearly. – jlsecrest Jun 21 '18 at 09:22

1 Answers1

6

I think you might be confused with something that confused me as well in the beginning. is is different than ==.

is will return True if two variables point to the same object.

== will return True if the variables point to objects that are equal.

The answer that helped me understand this is under this question: Is there a difference between == and is in Python?

Dora
  • 374
  • 3
  • 8
  • Ah. The question that you linked to does a great job of helping me understand. Thanks! So in these cases, it must be that python is "cach[ing] small integer objects, which is an implementation detail. For larger integers, this does not work:" – jlsecrest Jun 21 '18 at 09:17
  • 3
    To add a bit to the understanding. `x is y` has the same meaning as `id(x) == id(y)`. – user2653663 Jun 21 '18 at 09:22
  • @user2653663 your comment was really helpful for rounding out the idea. I updated my question to show what you're getting at for those who have the same question. – jlsecrest Jun 21 '18 at 09:38