DEV Community
Python doesn’t expose raw memory the way lower-level languages do, but you can still track how and when your variables change. In this tutorial, we’ll build a lightweight memory tracing tool using Python’s built-in sys.settrace
function, allowing us to monitor variable assignments and get insights into runtime behavior — no C extensions, no third-party tools.
Setup
This method works in pure Python 3. No dependencies needed. You’ll just need a working Python environment and a target function you want to introspect. It's particularly useful for debugging, reverse engineering, or building your own lightweight instrumentation tools.
Full Working Code
import sys
def trace_vars(frame, event, arg):
if event != "line":
return trace_vars
code = frame.f_code
lineno = frame.f_lineno
locals_now = frame.f_locals.copy()
global last_locals
if code.co_name not in last_locals:
last_locals[code.co_name] = locals_now
return trace_vars
old_locals = last_locals[code.co_name]
for var, new_val in locals_now.items():
if var not in old_locals:
print(f"[{code.co_name}:{lineno}] NEW {var} = {new_val}")
elif old_locals[var] != new_val:
print(f"[{code.co_name}:{lineno}] MODIFIED {var}: {old_locals[var]} → {new_val}")
for var in old_locals:
if var not in locals_now:
print(f"[{code.co_name}:{lineno}] DELETED {var}")
last_locals[code.co_name] = locals_now
return trace_vars
def monitor(func):
def wrapper(*args, **kwargs):
global last_locals
last_locals = {}
sys.settrace(trace_vars)
try:
return func(*args, **kwargs)
finally:
sys.settrace(None)
return wrapper
Example usage
@monitor
def run_example():
a = 10
b = a + 5
b = b * 2
del a
return b
run_example()
Explanation
By using sys.settrace
, we register a line-by-line callback that can introspect the current local variables at each step. We store a snapshot of the locals for each function, then compare it on the next invocation to detect changes — additions, updates, deletions. It’s a powerful (and often overlooked) way to understand the control and data flow of any Python function at runtime.
Pros & Cons
✅ Pros
- Works with unmodified Python
- Fully userland — no C or unsafe operations
- Easy to wrap around any function
- Valuable for introspection, testing, and education
⚠️ Cons
- Significant performance overhead
- Doesn’t work well with async or multithreaded code
- Can’t access native extensions or memory directly
- Not suitable for production monitoring
Summary
This approach gives you a window into the lifecycle of variables in Python, letting you trace changes without any third-party packages or tooling. While it's not a true memory inspector, it's a powerful pattern for anyone debugging tricky code or trying to understand execution in fine-grained detail.
If this was useful, you can Buy Me a Coffee ☕
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)