Counting the number of call of a function

L

Laurent Claessens

Hello


Is it possible to count the number of time a function is called ?
Of course, if I've access to the source code, it's easy.

I tried the following :

def foo():
print "foo !"


class wraper(object):
def __init__(self,fun):
globals()[fun]=self.replacement
def replacement(*args):
print "I'm replaced"

foo()
X=wraper(foo)
foo()

I was hoping that globals()[foo] would be replaced by my X.replacement
and thus the second call to foo() was expected to print "I'm replaced".

Instead nothing is done.

By the way, I tried to print globals() inside __init__() to see what
happens. It turns out that the entry 'foo' is never modified.

Any idea ?
I fact what I have to do is to add a decorator _a posteriori_ ...

Have a good night
Laurent
 
C

Chris Angelico

def foo():
   print "foo !"


class wraper(object):
   def __init__(self,fun):
       globals()[fun]=self.replacement
   def replacement(*args):
       print "I'm replaced"

foo()
X=wraper(foo)
foo()

Are you able to change the call structure to:

foo() # unchanged
foo=wrapper(foo) # this changes it
foo() # should now be changed

perhaps? That would be a lot easier to manage. Then you could write
the wrapper thus:

class wrapper(object):
def __init__(self,func):
self.func=func
def __call__(self,*args,**kwargs):
print("I'm replaced!") # if you want to be noisy
self.count+=1
self.func(*args,**kwargs)

Tested in Python 3; should also work in Python 2, which you appear to
be using. Effectively, I've written something that could actually be a
decorator, and then done the same sort of thing that a decorator does
by rebinding the name.

ChrisA
 
C

Chris Angelico

class wraper(object):
   def __init__(self,fun):
       globals()[fun]=self.replacement
   def replacement(*args):
       print "I'm replaced"

foo()
X=wraper(foo)
foo()

I was hoping that globals()[foo] would be replaced by my X.replacement and
thus the second call to foo() was expected to print "I'm replaced".

Actually, I've just realized what your problem might be. Try:
X = wraper("foo")

You're indexing globals() with the actual function object, but you
want to index it with the function _name_. I do think that the
decorator technique will be a lot cleaner, though.

ChrisA
 
M

MRAB

Hello


Is it possible to count the number of time a function is called ?
Of course, if I've access to the source code, it's easy.

I tried the following :

def foo():
print "foo !"


class wraper(object):
def __init__(self,fun):
globals()[fun]=self.replacement
def replacement(*args):
print "I'm replaced"

foo()
X=wraper(foo)
foo()

I was hoping that globals()[foo] would be replaced by my X.replacement
and thus the second call to foo() was expected to print "I'm replaced".

Instead nothing is done.

By the way, I tried to print globals() inside __init__() to see what
happens. It turns out that the entry 'foo' is never modified.

Any idea ?
I fact what I have to do is to add a decorator _a posteriori_ ...
The keys of globals() are the _names_. You're giving it the function
itself.

Try this:

class wraper(object):
def __init__(self,fun):
globals()[fun.__name__]=self.replacement
def replacement(*args):
print("I'm replaced")

A decorator would be better.
 
C

Chris Rebert

  Hello


  Is it possible to count the number of time a function is called ?
Of course, if I've access to the source code, it's easy.

I tried the following :

def foo():
   print "foo !"


class wraper(object):
   def __init__(self,fun):
       globals()[fun]=self.replacement
   def replacement(*args):
       print "I'm replaced"

foo()
X=wraper(foo)
foo()

I was hoping that globals()[foo] would be replaced by my X.replacement and
thus the second call to foo() was expected to print "I'm replaced".

Instead nothing is done.

That's because globals() maps names (i.e. strings) to values, whereas
in this case `fun` is a function object, not a string. Trying to
subscript globals() with a non-string arguably ought to be an error.

By way of example (with irrelevant stuff elided):

Python 2.6.6 (r266:84292, Jan 12 2011, 13:35:00)
Type "help", "copyright", "credits" or "license" for more information..... pass
....
globals()
{... said:
globals()[foo] = 42
globals()
{... said:
globals()["foo"] = 99
globals()
{..., 'foo': 99, <function foo at 0x378170>: 42}

Note that you can get the name of a function using its __name__
attribute. That is to say:
foo.__name__ == "foo"
By the way, I tried to print globals() inside __init__() to see what
happens. It turns out that the entry 'foo' is never modified.

Any idea ?
I fact what I have to do is to add a decorator _a posteriori_ ...

Recall that the decorator syntax:

@bar
def qux():
pass

is basically equivalent to:

def qux():
pass

qux = bar(qux)

Therefore, you want something like:

def wrapped(func):
def replacement(*args, **kwargs):
print "I'm replaced"
return replacement

foo = wrapped(foo)
foo() # => I'm replaced

Cheers,
Chris
 
L

Laurent Claessens

The keys of globals() are the _names_. You're giving it the function
itself.

Ow, ok. I didn't caught it. I understand now.
A decorator would be better.

Yes. I keep the solution with
foo=Wraper(foo)

Thanks a lot all !
Laurent
 
L

Laurent Claessens

The keys of globals() are the _names_. You're giving it the function
itself.

Ow, ok. I didn't caught it. I understand now.
A decorator would be better.

Yes. I keep the solution with
foo=Wraper(foo)

Thanks a lot all !
Laurent
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top