How can I get an object's previous location with Python?
The reason why the script doesn't work as expected is that you're keeping a reference to the object's data followed by a redo. This causes the reference to be invalid. Blender's Python API provides access to the underlying functionality implemented in C (or C++), which is why some precautions are necessary to avoid undefined behavior. Basically you're dereferencing a pointer to freed memory. The freed memory may still contain the old values, which is why in some cases you're still getting the correct result. However there is no guarantee for that since it's undefined behavior. 

The problem is explained in the Help! My script crashes Blender section in the Gotchas of the manual.


  TL;DR: Do not keep direct references to Blender data (of any kind) when
  modifying the container of that data, and/or when some undo/redo may
  happen (e.g. during modal operators execution…). Instead, use indices
  (or other data always stored by value in Python, like string keys…),
  that allow you to get access to the desired data.
  
  Ideally it would be impossible to crash Blender from Python however
  there are some problems with the API where it can be made to crash.
  
  Strictly speaking this is a bug in the API but fixing it would mean
  adding memory verification on every access since most crashes are
  caused by the Python objects referencing Blenders memory directly,
  whenever the memory is freed or re-allocated, further Python access to
  it can crash the script. But fixing this would make the scripts run
  very slow, or writing a very different kind of API which doesn’t
  reference the memory directly.


Your script can be fixed by creating a copy of the location.

oldLoc = bpy.context.active_object.location.copy()




Another possible issue could be that you're developing and running the script in Blender's text editor which is also part of the undo history. Editing the script appends a step in the history which is why the second time the script is run, you're not seeing the original location as in the previous run. Instead it's the "new" location, which was the current location when you were editing the script.

Putting the code in a function and executing it multiple times will show the same results for each function call.

import bpy


def undo_redo():
    bpy.ops.ed.undo()
    oldLoc = bpy.context.active_object.location.copy()
    bpy.ops.ed.redo()
    newLoc = bpy.context.active_object.location
    print(f'newLoc: {newLoc}\noldLoc: {oldLoc}\n---')

for i in range(3): 
    undo_redo()