Another idea if you really want to be able to do
foo = 5 and have it
behave the way you want:
Create a custom dictionary type to hold locals() (and perhaps globals() if needed). Unless I'm wrong, that dict type can pretty much do whatever you want, including overriding assignment behavior. Then just run the code using exec(), passing the custom hdl_locals().
You could package up a custom python interpreter for hardware programming which simply execs() the python code using this customized assignment behavior provided by hdl_locals(). Such a customized namespace is a very pythonic approach, and if I understand correctly, most regular non hdl python would probably be able to run.