Generators and Decorators doing my head in ..

S

simonvc

Hi Can someone please help me understand this (i shouldn't have tried
to learn decorators and generators at the same time..).

Im trying to create a decorator that counts the number of times a
function is run. Somthing like:

def FunctionCounter():
n=0
while 1:
yield n
n=n+1

def logFunctionCalls(function):
print "Entering function:", function.__name__, ec.next()
return function

@logFunctionCalls
def doWork():
print "Doing Work"


doWork()

Where "ec" is a generator that is created inside logFunctionCalls if it
doesnt already exist.
Im thinking this has somthing to do with anonymous generators, but im
not sure how you create or access these..

Apologies in advance if this is moronic.
 
P

Paul McGuire

Compare this to your original:

def logFunctionCalls(function):
ec = FunctionCounter()
def decoratedFunction(*args,**kwargs):
print "Entering function:", function.__name__, ec.next()
function(*args,**kwargs)
return decoratedFunction

@logFunctionCalls
def doWork():
print "Doing Work"

doWork()
doWork()

(This is a quick-and-dirty example, but it works. A proper iterator
would do more to preserve the identity, docstring, etc. of the
underlying doWork() function. See the decorator library page on the
Python Wiki, at http://wiki.python.org/moin/PythonDecoratorLibrary.)

Also, look into the treasure trove that is itertools, especially
itertools.count.

-- Paul
 
L

Leif K-Brooks

Im trying to create a decorator that counts the number of times a
function is run.

Your code doesn't work because decorators are run at function creation
time, not at function run time. Try this instead:


from itertools import count

def logFunctionCalls(function):
times = count()
def newfunction(*args, **kwargs):
print "Entering function:", function.__name__, times.next()
return function(*args, **kwargs)
newfunction.__doc__ = function.__doc__
newfunction.__name__ = function.__name__
return newfunction

@logFunctionCalls
def doWork():
print "Doing work..."
 
S

simonvc

Fantastic, thanks Leif and Paul, My problem is that i thought the
decorator worked at the function runtime, not when the function gets
created.
 
M

Michele Simionato

I usually point out my decorator module
(http://www.phyast.pitt.edu/~micheles/python/decorator.zip) to simplify
decorator usage. In this case you would use it as follows:

from decorator import decorator

@decorator # convert logFunctionCalls into a decorator
def logFunctionCalls(function, *args, **kwargs):
try: # increment the counter
function.counter += 1
except AttributeError: # first call, there is no counter attribute
function.counter = 1
print "Entering function:", function.__name__, function.counter
return function(*args, **kwargs)

@logFunctionCalls
def f():
pass

f()
f()
f()

help(f)

The whole point of the decorator module is that the signature of
the original function is left unchanged (i.e. in this case the
decorated f is still a thunk, not a generic function f(*args, **kw)).
HTH,

Michele Simionato
 

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

Staff online

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top