Search code examples
pythonpython-3.xanacondaspyderanaconda3

Python: Behaviour of float memory addressing


All, When I execute the following code from inside Spyder IDE, I get the same ID of a, b, and the number 1000., yet when I execute the code from the Spyder console, I get different IDs (the ID of a is different from b). Floats are known to be immutable, yet they behave like mutable when executed by the spyder editor. Any idea why this is the case.

a=1000.
b=1000.
print('id of a='+str(id(a)))
print('id of b='+str(id(b)))
print('id of 1.'+str(id(1000.)))

Thanks


Solution

  • This has nothing to do with Spyder, this is purely a Python optimisation, as kindly explained by @Barmar.

    Example 1: Line-based execution

    When the values are assigned for line-execute (even if the lines are grouped when executed), the following output is provided:

    >>> a = 1000.
    >>> b = 1000.
    >>> print(f'{id(a)=}\n{id(b)=}')
    
    id(a)=140093502852336
    id(b)=140093502851184
    

    Different IDs.

    Example 2: Function-based execution

    However, when the assignments are wrapped in a function (as shown below), Python performs optimisations which basically say: "Hey, I've got a variable for that value already, so I'll just use it again."

    def test():
        a = 1000.
        b = 1000.
        print(f'{id(a)=}\n{id(b)=}')
    
    >>> test()
    id(a)=140093502851472
    id(b)=140093502851472
    

    Same IDs.


    Bytecode: Function-based execution

    As shown in the bytecode for the test() function, the same ID has been assigned to the variables, due to compiler optimisations.

      2           0 LOAD_CONST               1 (1000.0)  # <-- Here (1)
                  2 STORE_FAST               0 (a)
    
      3           4 LOAD_CONST               1 (1000.0)  # <-- Here (1)
                  6 STORE_FAST               1 (b)
    
      4           8 LOAD_GLOBAL              0 (print)
                 10 LOAD_CONST               2 ('id(a)=')
                 12 LOAD_GLOBAL              1 (id)
                 14 LOAD_FAST                0 (a)
                 16 CALL_FUNCTION            1
                 18 FORMAT_VALUE             2 (repr)
                 20 LOAD_CONST               3 ('\nid(b)=')
                 22 LOAD_GLOBAL              1 (id)
                 24 LOAD_FAST                1 (b)
                 26 CALL_FUNCTION            1
                 28 FORMAT_VALUE             2 (repr)
                 30 BUILD_STRING             4
                 32 CALL_FUNCTION            1
                 34 POP_TOP
                 36 LOAD_CONST               0 (None)
                 38 RETURN_VALUE