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(), because hasattr() 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.)

These are my WanderingThoughts
(About the blog)

GettingAround
Full index of entries
Recent comments

This is part of CSpace, and is written by ChrisSiebenmann.

* * *

Atom feeds are available; see the bottom of most pages.

This is a DWiki.
(Help)

Categories: links, linux, programming, python, snark, solaris, spam, sysadmin, tech, unix, web

Search:
Written on 01 April 2008.
(Previous | Next)

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Tue Apr 1 22:33:28 2008
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.