2

I read a question earlier asking if there was a times method in Python, that would allow a function to be called n times in a row.

Everyone suggested for _ in range(n): foo() but I wanted to try and code a different solution using a function decorator.

Here's what I have:

def times(self, n, *args, **kwargs):
    for _ in range(n):
        self.__call__(*args, **kwargs)

import new
def repeatable(func):
    func.times = new.instancemethod(times, func, func.__class__)

@repeatable
def threeArgs(one, two, three):
    print one, two, three

threeArgs.times(7, "one", two="rawr", three="foo")

When I run the program, I get the following exception:

Traceback (most recent call last):
  File "", line 244, in run_nodebug
  File "C:\py\repeatable.py", line 24, in 
    threeArgs.times(7, "one", two="rawr", three="foo")
AttributeError: 'NoneType' object has no attribute 'times'

So I suppose the decorator didn't work? How can I fix this?

1
  • 1
    This method seems to be less idiomatic and less simple than the one you are replacing. Commented Apr 17, 2010 at 23:09

3 Answers 3

3

Your decorator should return the function object:

def repeatable(func):
    func.times = new.instancemethod(times, func, func.__class__)
    return func

Now it returns nothing, so you actually change threeArgs in a None

This is because this:

@decorator
def func(...):
    ...

is more or less the same as:

def func(...):
    ....
func = decorator(func)
Sign up to request clarification or add additional context in comments.

1 Comment

awesome, I guess I should have figured... oh well, thanks for your help
1

You're missing a return func statement at the end of your repeatable decorator.

Comments

0

Have you considered not adding it to specific functions and instead allowing its use with any function?

def times(n, func, *args, **kwds):
  return [func(*args, **kwds) for _ in xrange(n)]

(I'm returning a list of return values, but you could write it to ignore them, similar to the for-loop you have in the question.)

Then where you would, with your version, use:

threeArgs.times(7, "one", two="rawr", three="foo")

You instead use:

times(7, threeArgs, "one", two="rawr", three="foo")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.