we can get tensor measurements by writing something like:
qml.expval(qml.PauliZ(0) @ PauliZ(1))

but is there a way to automate this if I have a variable number of qubits?
Something which might work like:
qml.expval(TENSOR [qml.PauliZ(i) for i in (range(n_qubits))])

this is already possible for local measurements.

If this is something simple that is skipping me right now, I apologise!

Hey @ankit27kh! Yes, there are two ways of doing this

Method 1:

from pennylane.operation import Tensor
@qml.qnode(dev)
...
return qml.expval(Tensor(*[qml.PauliZ(i) for i in range(n_qubits)]))

Method 2:

from functools import reduce
import operator
@qml.qnode(dev)
...
obs = reduce(operator.matmul, [qml.PauliZ(i) for i in range(n_qubits)])
return qml.expval(obs)