Surprised by the lack of constant folding

Chris Angelico rosuav at gmail.com
Fri Mar 24 15:49:13 EDT 2017


On Sat, Mar 25, 2017 at 6:35 AM, Tim Chase
<python.list at tim.thechases.com> wrote:
> $ python3
> Python 3.4.2 (default, Oct  8 2014, 10:45:20)
> [GCC 4.9.1] on linux
> Type "help", "copyright", "credits" or "license" for more information.
>>>> from dis import dis
>>>> def f(x):
> ...     return x * 1024 * 1024
> ...
>>>> dis(f)
>   2           0 LOAD_FAST                0 (x)
>               3 LOAD_CONST               1 (1024)
>               6 BINARY_MULTIPLY
>               7 LOAD_CONST               1 (1024)
>              10 BINARY_MULTIPLY
>              11 RETURN_VALUE
>
> Is there any reason that Python doesn't do the constant folding of
> 1024 * 1024?  Especially as it does constant folding if the order is
> reversed:
>
>>>> def f(x):
> ...     return 1024 * 1024 * x
> ...
>>>> dis(f)
>   2           0 LOAD_CONST               2 (1048576)
>               3 LOAD_FAST                0 (x)
>               6 BINARY_MULTIPLY
>               7 RETURN_VALUE
>
>
> I'm cool with defining things as a constant and using those instead
> or front-loading my constants in my expressions, but the disparity
> struck me as a little odd.  Any insights on the reasons/motivations
> for one and not the other?

The first example is:

(x * 1024) * 1024

The second is:

(1024 * 1024) * x

The first one can't be constant-folded without a semantic change
(Python can't know that x will always be a number, even if you do).
Suggestion: Use a different operator, which binds more tightly.

>>> def f(x):
...     return x * 2**20
...
>>> dis(f)
  2           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               3 (1048576)
              4 BINARY_MULTIPLY
              6 RETURN_VALUE

Since this evaluates as x * (2**20), it can be constant-folded.

ChrisA


More information about the Python-list mailing list