Does python reuse repeated calculation results? Does python reuse repeated calculation results? python python

Does python reuse repeated calculation results?


You can check that with dis.dis. The output is:

  2           0 LOAD_CONST               0 (1)              2 STORE_NAME               0 (x)  3           4 LOAD_CONST               1 (2)              6 STORE_NAME               1 (y)  4           8 LOAD_CONST               2 (3)             10 STORE_NAME               2 (z)  5          12 LOAD_NAME                0 (x)             14 LOAD_NAME                1 (y)             16 BINARY_ADD             18 LOAD_NAME                2 (z)             20 BINARY_ADD             22 LOAD_CONST               0 (1)             24 BINARY_ADD             26 LOAD_NAME                0 (x)             28 LOAD_NAME                1 (y)             30 BINARY_ADD             32 LOAD_NAME                2 (z)             34 BINARY_ADD             36 LOAD_CONST               1 (2)             38 BINARY_ADD             40 BINARY_ADD             42 STORE_NAME               3 (r)             44 LOAD_CONST               3 (None)             46 RETURN_VALUE

So it won't cache the result of the expression in parentheses. Though for that specific case it would be possible, in general it is not, since custom classes can define __add__ (or any other binary operation) to modify themselves. For example:

class Foo:    def __init__(self, value):        self.value = value    def __add__(self, other):        self.value += 1        return self.value + otherx = Foo(1)y = 2z = 3print(x + y + z + 1)  # prints 8print(x + y + z + 1)  # prints 9

If you have an expensive function of which you would like to cache the result, you can do so via functools.lru_cache for example.

On the other hand, the compiler will perform constant folding as can be seen from the following examples:

>>> import dis>>> dis.dis("x = 'abc' * 5")  1           0 LOAD_CONST               0 ('abcabcabcabcabc')              2 STORE_NAME               0 (x)              4 LOAD_CONST               1 (None)              6 RETURN_VALUE>>> dis.dis("x = 1 + 2 + 3 + 4")  1           0 LOAD_CONST               0 (10)              2 STORE_NAME               0 (x)              4 LOAD_CONST               1 (None)              6 RETURN_VALUE


EDIT: This answer applies only to the default CPython interpreter of the Python language. It may not be applicable to other Python implementations that adopts JIT compilation techniques or uses a restricted Python sublanguage that allows static type inference. See @Jörg W Mittag's answer for more details.

No it will not. You can do this to see the compiled code:

from dis import disdis("r=(x+y+z+1) + (x+y+z+2)")

Output:

          0 LOAD_NAME                0 (x)          2 LOAD_NAME                1 (y)          4 BINARY_ADD          6 LOAD_NAME                2 (z)          8 BINARY_ADD         10 LOAD_CONST               0 (1)         12 BINARY_ADD         14 LOAD_NAME                0 (x)         16 LOAD_NAME                1 (y)         18 BINARY_ADD         20 LOAD_NAME                2 (z)         22 BINARY_ADD         24 LOAD_CONST               1 (2)         26 BINARY_ADD         28 BINARY_ADD         30 STORE_NAME               3 (r)         32 LOAD_CONST               2 (None)         34 RETURN_VALUE

This is partially because Python is dynamically-typed. So the types of variables are not easily known at compile time. And the compiler has no way to know whether the + operator, which can be overloaded by user classes, could have any side effect at all. Consider the following simple example:

class A:    def __init__(self, v):        self.value = v    def __add__(self, b):        print(b)        return self.value + bx = A(3)y = 4r = (x + y + 1) + (x + y + 2)

For simple expressions, you can just save the intermediate results to a new variable:

z = x + y + 1r = z + (z + 1)

For functions calls, functools.lru_cache is another option, as already indicated by other answers.


If I have an expression that I wish to evaluate in Python, such as the expression for r in the code snippet below, will the Python interpreter be smart and reuse the subresult x+y+z, or just evaluate it twice?

Which Python interpreter are you talking about? There are currently four production-ready, stable Python implementations in widespread use. None of those actually have a Python interpreter, every single one of them compiles Python.

Some of them may or may not be able to perform this optimization for at least some programs under at least some circumstances.

The Python Language Specification does neither require nor forbid this kind of optimization, so any specification-conforming Python implementation would be allowed to, but not required, to perform this optimization.

I am pretty certain that, contrary to all the other answers which state that Python cannot do this, PyPy is capable of performing this optimization. Also, depending on which underlying platform you use, code executed using Jython or IronPython will also benefit from this optimization, e.g. I am 100% certain that the C2 compiler of Oracle HotSpot does perform this optimization.

I'd also be interested to know if the answer to this question would be the same for a compiled language […].

There is no such thing as a "compiled language". Compilation and interpretation are traits of the compiler or interpreter (duh!) not the language. Every language can be implemented by a compiler, and every language can be implemented by an interpreter. Case in point: there are interpreters for C, and conversely, every currently existing production-ready, stable, widely-used implementation of Python, ECMAScript, Ruby, and PHP has at least one compiler, many even have more than one (e.g. PyPy, V8, SpiderMonkey, Squirrelfish Extreme, Chakra).

A language is an abstract set of mathematical rules and restrictions written on a piece of paper. A language is neither compiled nor interpreted, a language just is. Those concepts live on different layers of abstraction; if English were a typed language, the term "compiled language" would be a type error.

I'd also be interested to know if the answer to this question would be the same for […] e.g. C.

There are many production-ready, stable C implementations in widespread use. Some of them may or may not be able to perform this optimization for at least some programs under at least some circumstances.

The C Language Specification does neither require nor forbid this kind of optimization, so any specification-conforming C implementation would be allowed to, but not required, to perform this optimization.