There's actually a really great way to evaluate this with Qiskit Aqua's operator logic.
This module has the concept of statefunctions to represent $|\Psi\rangle$ and $\langle\Psi |$ and operators to represent operators such as $Z^{\otimes n}$.
Your operator would be created using the $Z$ primitive:
from qiskit.aqua.operators import Z
operator = Z ^ Z # ^ represents a tensor product
operator = Z ^ 2 # same thing, computes Z ^ Z
operator = Z.tensorpower(2) # same thing as Z ^ 2
Now you need to create your state $|\Psi\rangle$, for which you have different options. Say you know the circuit to prepare your state, then you can do
from qiskit import QuantumCircuit
from qiskit.aqua.operators import StateFn
psi_circuit = QuantumCircuit(2)
# prepare your state ..
psi = StateFn(psi_circuit) # wrap it into a statefunction
Or you can also use prepared common statefunctions such as Zero
= $|0\rangle$, One
= $|1\rangle$, Plus
= $|+\rangle$ or Minus
= $|-\rangle$,
from qiskit.aqua.operators import Zero, Plus
psi = Zero ^ Plus # creates the state |0+>
To compute the expectation value you naturally need to evaluate $\langle \Psi | ZZ | \Psi\rangle$, which you can do as
expectation_value = (~psi @ operator @ psi).eval()
expectation_value = (psi.adjoint().compose(operator).compose(psi)).eval() # same as above
To explain the syntax: ~
computes the adjoint, so ~psi
= $\langle\Psi|$. The @
sign is composition and sticks together your states and operators.
Full example
As an example, let's compute the expectation value of $\langle \Psi| ZZ | \Psi\rangle$ with $|\Psi\rangle = \frac{1}{\sqrt{2}} (|01\rangle + |10\rangle)$.
Calculating by hand, this should yield $-1$.
import numpy as np
from qiskit.aqua.operators import Z, Zero, One
operator = Z ^ Z
psi = 1 / np.sqrt(2) * ((One ^ Zero) + (Zero ^ One))
expectation_value = (~psi @ operator @ psi).eval()
print(expectation_value.real) # -1.0