Добавление метода к объекту функции во время выполнения - PullRequest
2 голосов
/ 18 апреля 2010

Ранее я прочитал вопрос, спрашивающий, существует ли в Python метод times, который позволял бы вызывать функцию n раз подряд.

Все предлагали for _ in range(n): foo(), но я хотел попробовать написать другое решение, используя функцию декоратора.

Вот что у меня есть:

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")

Когда я запускаю программу, я получаю следующее исключение:

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'

Итак, я полагаю, декоратор не работал? Как я могу это исправить?

Ответы [ 3 ]

3 голосов
/ 18 апреля 2010

Ваш декоратор должен вернуть объект функции:

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

Теперь он ничего не возвращает, так что вы фактически меняете три арга в None

Это потому что это:

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

более или менее совпадает с:

def func(...):
    ....
func = decorator(func)
1 голос
/ 18 апреля 2010

Вам не хватает оператора return func в конце вашего repeatable декоратора.

0 голосов
/ 18 апреля 2010

Рассматривали ли вы, что не добавляете его к определенным функциям и разрешаете использовать его с любой функцией?

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

(я возвращаю список возвращаемых значений, но вы можете написать его, чтобы игнорировать их, аналогично циклу for, который у вас есть в вопросе.)

Тогда где бы вы, в своей версии, использовали:

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

Вместо этого вы используете:

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