Seemingly odd 'is' comparison.

Arnaud Delobelle arnodel at googlemail.com
Tue Feb 19 12:54:14 EST 2008


On Feb 19, 1:47 pm, Boris Borcic <bbor... at gmail.com> wrote:
> Arnaud Delobelle wrote:
> > On Feb 13, 10:19 pm, Tobiah <t... at tobiah.org> wrote:
> >>>>> print float(3.0) is float(3.0)
> >> True
> >>>>> print float(3.0 * 1.0) is float(3.0)
> >> False
>
> > [You don't need to wrap your floats in float()]
>
> >>>> def f():
> > ...     return 3.0 is 3.0, 3.0*1.0 is 3.0
> > ...
> >>>> f()
> > (True, False)
> >>>> import dis
> >>>> dis.dis(f)
> >   2           0 LOAD_CONST               1 (3.0)
> >               3 LOAD_CONST               1 (3.0)
> >               6 COMPARE_OP               8 (is)
> >               9 LOAD_CONST               3 (3.0)
> >              12 LOAD_CONST               1 (3.0)
> >              15 COMPARE_OP               8 (is)
> >              18 BUILD_TUPLE              2
> >              21 RETURN_VALUE
>
> > As you can see when "3.0 is 3.0" is evaluated the same float object is
> > put on the stack twice so the 'is' comparison is True (LOAD_CONST 1 /
> > LOAD_CONST 1 / COMPARE_OP 8).
>
> > Whereas when "3.0*1.0 is 3.0" is evaluated, *two* different float
> > objects are put on the stack and compared (LOAD_CONST 3 / LOAD_CONST
> > 1 / COMPARE_OP 8).  Therefore the result is False.
>
> Looks good, but doesn't pass the sanity check ;) Consider
>
>  >>> def f():
>         return 3 is 3, 3*1 is 3
>
>  >>> import dis
>  >>> dis.dis(f)
>    2           0 LOAD_CONST               1 (3)
>                3 LOAD_CONST               1 (3)
>                6 COMPARE_OP               8 (is)
>                9 LOAD_CONST               3 (3)
>               12 LOAD_CONST               1 (3)
>               15 COMPARE_OP               8 (is)
>               18 BUILD_TUPLE              2
>               21 RETURN_VALUE
>  >>> f()
> (True, True)
>
> Cheers, BB

Looks good, but doesn't pass the sanity check ;) Consider:

>>> def f():
...     return 1000000 is 1000000, 1000000*1 is 1000000
...
>>> f()
(True, False)
>>> dis.dis(f)
  2           0 LOAD_CONST               1 (1000000)
              3 LOAD_CONST               1 (1000000)
              6 COMPARE_OP               8 (is)
              9 LOAD_CONST               3 (1000000)
             12 LOAD_CONST               1 (1000000)
             15 COMPARE_OP               8 (is)
             18 BUILD_TUPLE              2
             21 RETURN_VALUE

Small integers are special because they are interned, that's why you
got True for the second comparison.  With a larger integer that
doesn't happen.

--
Arnaud




More information about the Python-list mailing list