(answering to the OP)

Piyush Anonymous wrote:
i wrote this code
--
class Person(object):
    instancesCount = 0
    def __init__(self, title=""):
        Person.instancesCount += 1
        self.id <http://self.id> = "tempst"
    def testprint(self):
        print "blah blah"
    def __getattribute__(self, name):
        print "in get attribute"

a = Person()
a.testprint()
print a.id <http://a.id>
-----
but i am getting this error
----
in get attribute
Traceback (most recent call last):
  File "trapmethodcall1.py", line 15, in <module>
    a.testprint()
TypeError: 'NoneType' object is not callable
------
why is it so? __getattribute__ is called whenever an attribute or method is called, rt?


Yes. Methods are attributes too. And __getattribute__ is the attribute lookup operator implementation - it is invoked *everytime* you have obj.attr or getattr(obj, "attr") or hasattr(obj, "attr"). IOW, you'd better *not* touch it unless 1/ you really know what you're doing, 2/ you have a very compelling reason to do so and 3/ you're ok to pay the performance hit (the default implementation in 'object' being optimized).


or if i set __getattribute__ , i cannot have methods in class?

Yes, you can. But you have to write a proper implementation of __getattribute__. The one above will prevent you from accessing any class or instance attribute (or, more exactly, will always return None).

actually my aim is to trap all method calls and keep a counter which is update whenever method called or returned. how should i go about it?


Using __getattribute__, you'll only get at the method when it is looked up (which doesn't imply it will be called). If you want to log calls and returns, you'll have to wrap the method in a decorator. You can do this either manually (ie manually adding the logger decorator on methods), via monkeypatching on class objects (but this can be tricky too), or adding a properly implemented version of __getattribute__ (but this won't work if the method is looked up on the class itself)

# a Q&D method call logger

def log(meth):
    if hasattr(meth, "logged"):
        # already wrapped
        return meth

    def logged(*args, **kw):
        if hasattr(meth, "im_self"):
            # wrapping a method
            what = "method %s " % meth
        else:
            # wrapping a function, 'self' or 'cls' is the first arg
            what = "method %s of object %s" % (meth, args[0])
        print "%s called with %s %s" % (what, str(args), kw)
        try:
            result = meth(*args, **kw)
        except Exception, e:
            print "%s raised %s" % (what, e)
            raise
        else:
            print "%s returned %s" % (what, str(result))
        return result
    logged.logged = True
    return logged


# manual decoration

class Foo(object):
    @log
    def bar(self):
        pass


# using __getattribute__

class Foo(object):
    def bar(self):
        pass
    def __getattribute__(self, name):
        attr = super(Foo2, self).__getattribute__(name)
        if hasattr(attr, "im_self"):
            attr = log(attr)
        return attr



Given the shortcomings of the __getattribute__ version (performance hit and only triggered on instance lookup), I'd strongly suggest the manual decoration - possibly using a flag (global setting or environment variable) to switch it off, ie:

if globals().get("DEBUG", False):
    def log(func):
        def logged(*args, **kw):
            # wrapping a function
            # we assume this function is used as a method, so
            # 'self' or 'cls' is the first arg
            what = "method %s of object %s" % (func, args[0])
            print "%s called with %s %s" % (what, str(args), kw)
            try:
                result = func(*args, **kw)
            except Exception, e:
                print "%s raised %s" % (what, e)
                raise
            print "%s returned %s" % (what, str(result))
            return result
    return logged
else:
    def log(func):
        # no-op
        return func

NB : all this is pretty Q&D and mostly untested, but it should get you started.


HTH
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to