pythoncompiler-optimization

Is it possible for the Python compiler to optimize away some integer arithmetic?


Inspired by this question about Python caching small integers.

Is it possible for the Python compiler to replace (0 - 6) with -6 at compile time? The code below suggests that it does not. If it is not possible, why not? I don't think that the meaning of 0, -, or 6 can be different at run time.

If this is possible, why does CPython not do it?

# test_integers.py
def test_integers():
    print "-6 is -6 ?", -6 is -6 # True
    print "(0 - 6) is -6 ?", (0 - 6) is -6 # False

# import_test_integers.py
import test_integers
test_integers.test_integers()

My Python details in case this is very implementation-dependent:

Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56) 
[GCC 4.4.3] on linux2

Solution

  • First, you shouldn't be using is to compare integer values to detect optimizations. That has nothing to do with anything, as explained in the question you linked. If you want to know what optimizations were performed on your function, use the dis module, which produces (in 2.7.2):

    >>> import dis
    >>> 
    >>> def test_integers():
    ...     print "-6 is -6 ?", -6 is -6 # True
    ...     print "(0-6) is -6 ?", (0 - 6) is -6 # False
    ... 
    >>> dis.dis(test_integers)
      2           0 LOAD_CONST               1 ('-6 is -6 ?')
                  3 PRINT_ITEM          
                  4 LOAD_CONST               2 (-6)
                  7 LOAD_CONST               2 (-6)
                 10 COMPARE_OP               8 (is)
                 13 PRINT_ITEM          
                 14 PRINT_NEWLINE       
    
      3          15 LOAD_CONST               3 ('(0-6) is -6 ?')
                 18 PRINT_ITEM          
                 19 LOAD_CONST               6 (-6)
                 22 LOAD_CONST               2 (-6)
                 25 COMPARE_OP               8 (is)
                 28 PRINT_ITEM          
                 29 PRINT_NEWLINE       
                 30 LOAD_CONST               0 (None)
                 33 RETURN_VALUE        
    

    and you see that the subtraction actually was optimized away. You can see some others, too:

    >>> def f():
    ...     x = 1+2
    ...     x = 2-3
    ...     x = 3*4
    ...     x = 4/5
    ...     x = 5**6
    ... 
    >>> dis.dis(f)
      2           0 LOAD_CONST               7 (3)
                  3 STORE_FAST               0 (x)
    
      3           6 LOAD_CONST               8 (-1)
                  9 STORE_FAST               0 (x)
    
      4          12 LOAD_CONST               9 (12)
                 15 STORE_FAST               0 (x)
    
      5          18 LOAD_CONST               4 (4)
                 21 LOAD_CONST               5 (5)
                 24 BINARY_DIVIDE       
                 25 STORE_FAST               0 (x)
    
      6          28 LOAD_CONST              10 (15625)
                 31 STORE_FAST               0 (x)
                 34 LOAD_CONST               0 (None)
                 37 RETURN_VALUE