How do i detect or capture change of value of a global variable in python
variable = 10
print(variable)
variable = 20
# Detect changes to the value using a signal to trigger a function
UPDATE
AST docs - GOOD INTRO
https://greentreesnakes.readthedocs.io/en/latest/
To my knowledge, it is not possible to generically capture the assignment of a global symbol in Python (At least in CPython where globals are stored in a dict
in the module
object, both are C types that cannot be monkey patched).
Here's a simple workaround that's a bit of a compromise. Use a wrapper object to store your monitored variables, and define __setattr__
to do whatever you want to do before (or after) setting an attribute.
class CaptureOnSetAttribute:
def __setattr__(self, attr, value):
# our hook to do something
print(f'set value of {attr} to {value}')
# actually set the attribute the normal way after
super().__setattr__(attr, value)
wrapper_object = CaptureOnSetAttribute()
The compromise of course is that now instead of writing something like:
monitored_global = value
You must now write:
wrapper_object.monitored_attribute = value
How about instrument the bytecode to add a print statement before each statement that stores to the global variable. Here is an example:
from bytecode import *
def instr_monitor_var(func, varname):
print_bc = [Instr('LOAD_GLOBAL', 'print'), Instr('LOAD_GLOBAL', varname),
Instr('CALL_FUNCTION', 1), Instr('POP_TOP')]
bytecodes = Bytecode.from_code(func.__code__)
for i in reversed(range(len(bytecodes))):
if bytecodes[i].name=='STORE_GLOBAL' and bytecodes[i].arg==varname:
bytecodes[i:i]=print_bc
func.__code__=bytecodes.to_code()
def test():
global a
a = 1
instr_monitor_var(test, 'a')
test()
instr_monitor_var
can instrument a function test
so the global variable a
will be printed out when its value is changed. Let me know if this works. Thanks!