A simple Python class to trace access to object attributes
Every now and then I run into a situation where I want to know what attributes on an object are getting accessed when. Fortunately it's pretty easy to knock together something to do this, in a variant on the mutating proxy pattern.
Here is a sample implementation, as a Tracer
class:
def _repon(obj, n): return (not obj._t_il) or \ (n in obj._t_il) class Tracer(object): def __init__(self, real, name = None, monitor = None): self._t_ro = real if name: self._t_nm = name else: cl = real.__class__ self._t_nm = "<%s.%s>" % \ (cl.__module__, cl.__name__) self._t_il = monitor def __getattr__(self, n): if _repon(self, n): print "get %s.%s" % (self._t_nm, n) return getattr(self._t_ro, n) def __setattr__(self, n, v): if n in ("_t_nm", "_t_ro", "_t_il"): super(Tracer, self).__setattr__(n, v) return if _repon(self, n): print "set %s.%s" % (self._t_nm, n) setattr(self._t_ro, n, v) def __delattr__(self, n): if _repon(self, n): print "del %s.%s" % (self._t_nm, n) delattr(self._t_ro, n)
You use it by replacing the original object with Tracer(obj)
. The
optional name
argument will be used as the object's name in output;
the optional monitor
argument is a list of attributes to monitor
access to (if omitted, all attributes are monitored).
There's a couple of limitations in this approach:
- 'get' is printed when you do
hasattr()
, becausehasattr()
works by getting the attribute and seeing if that throws an error. - you can't tell a method call from an attribute access, because Python doesn't really distinguish them.
As a side note, the _repon
function is not a class function in order
to keep it out of the object namespace. I could keep the three variables
out too if I wanted to work hard enough, by using a closure, but that
would complicate and obscure the code.
(Disclaimer: the indentation has been shrunk and the variable names shortened in the interests of not overflowing WanderingThoughts' margins. I do not write real code that is this condensed.)
|
|