traceing object usage: how to trace attribute access

Volker Apelt gq437x at
Wed Mar 5 15:11:54 CET 2003

I am looking for ways to trace all kind of access to objects
of some class with least impact on the traced class and 
no impact on the caller.

I have already found some code written by Greg Chapman 
(glchapman at on google, which traces  
object method calls using __getattribute__. (see below)
With a small extension it traces all kinds 
of object attribute access, too.  

But it can not tell whether it is read or write 
access to  object attributes.
And it traces all access, even from inside the same 

How can I find out, if this call of __getattribute__ 
is a read or a write (assign) to some attribute?

  other = C()
  print other.x # read access
  other.x = 1   # write access 

How can I find out, if this call of __getattribute__ 
is from with in the same instance of this object, 
like in self.x ?
  self.x  # internal access
  other.x # external access 
Thank you,


# code of  Greg Chapman with modifications 
import sys, types 
class Traced(object):
    traceStream = sys.stdout
    callNo = long(1)
    def __trace_call__(self, fp, fmt, *args):
        if fp is None:
            fp = Traced.traceStream
        fp.write((fmt+'\n') % args)

    def __getattribute__(self, name):
        res = super(Traced, self).__getattribute__(name)
        if name == '__trace_call__' or name == '__class__':
            return res
        if isinstance(res, types.MethodType):
            if self.__class__.traceStream:
                fullname = self.__class__.__name__ + "." + name
                res = TracingWrapper(fullname, res, self)
            fullname = self.__class__.__name__ + "." + name
            self.__trace_call__(None, "ACCESS: %s %s",fullname, res )
        return res

class TracingWrapper(object):
    def __init__(self, name, func, inst):
        self.__name__ = name
        self.func = func
        self.inst = inst

    def __call__(self, *args, **kw):
        callNo =  Traced.callNo
        Traced.callNo += 1
        out = None
                                 "CALL: %05d inst=%s, %s(  args=%s, kw=%s)",
                                 callNo,self.inst, self.__name__, args, kw)
            rv = self.func(*args, **kw)
            t, v, tb = sys.exc_info()
                                     "EXCEPTION: %05d %s, exception= %s: %s",
                                     callNo,self.__name__, t, v)
            raise t, v, tb
                                     "RETURN: %05d %s  value=%s",
                                     callNo,self.__name__, rv)
            return rv

if __name__ == '__main__':
    #### TEST CASE

    class C(Traced):#{
        def __init__(self, x=0): self.x = x
        def m1(self, x): self.x = x
        def m2(self, y): 
            self.x += 1
            return self.x + y
        def raise_if2(self,x):
            if x == 2:
                raise ValueError('forced execption x == 2')
            return self.x 
    c = C()

    c.x = 2
    except Exception,e:
        print '**** EXCEPTION',e

    print c.x

Volker Apelt                   

More information about the Python-list mailing list