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 + other

x = Foo(1)
y = 2
z = 3
print(x + y + z + 1)  # prints 8
print(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 dis
dis("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 + b

x = A(3)
y = 4
r = (x + y + 1) + (x + y + 2)

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

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

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