Подсчет вызовов метода python в рамках другого метода

Я на самом деле пытаюсь сделать это на Java, но я сейчас участвую в python, и это заставило меня задуматься, был ли простой / умный способ сделать это с помощью оберток или что-то в этом роде.

Я хочу знать, сколько раз был вызван конкретный метод внутри другого метода. Например:

def foo(z): #do something return result def bar(x,y): #complicated algorithm/logic involving foo return foobar 

Поэтому для каждого вызова бар с различными параметрами я хотел бы знать, сколько раз было вызвано foo, возможно, с выходом следующим образом:

 >>> print bar('xyz',3) foo was called 15 times [results here] >>> print bar('stuv',6) foo was called 23 times [other results here] 

edit: Я понимаю, что могу просто похлопать счетчик внутри бара и сбросить его, когда вернусь, но было бы здорово, если бы была какая-то магия, которую вы могли бы сделать с обертками, чтобы выполнить одно и то же. Это также означало бы, что я мог бы использовать одни и те же обертки в другом месте, не изменяя код внутри метода.

  • Столбец Pandas связывает (cbind) два кадра данных
  • Переменные python являются указателями?
  • Как установить цвет фона QWidget?
  • Django vs web2py для начинающего разработчика
  • Событие для текста в текстовом виджете Tkinter
  • Напротив numpy.unwrap
  • Несколько штук шаблонов jinja2?
  • Как получить строку за строкой MySQL ResultSet в python
  • 3 Solutions collect form web for “Подсчет вызовов метода python в рамках другого метода”

    Звучит почти как пример учебника для декораторов!

     def counted(fn): def wrapper(*args, **kwargs): wrapper.called+= 1 return fn(*args, **kwargs) wrapper.called= 0 wrapper.__name__= fn.__name__ return wrapper @counted def foo(): return >>> foo() >>> foo.called 1 

    Вы даже можете использовать другой декоратор для автоматизации записи того, сколько раз функция вызывается внутри другой функции:

     def counting(other): def decorator(fn): def wrapper(*args, **kwargs): other.called= 0 try: return fn(*args, **kwargs) finally: print '%s was called %i times' % (other.__name__, other.called) wrapper.__name__= fn.__name__ return wrapper return decorator @counting(foo) def bar(): foo() foo() >>> bar() foo was called 2 times 

    Если «foo» или «bar» могут в конечном итоге называть себя, вам понадобится более сложное решение, включающее стеки, чтобы справиться с рекурсией. Затем вы направляетесь в полнофункциональный профайлер …

    Возможно, этот обернутый материал декоратора, который, как правило, используется для магии, не является идеальным местом для поиска, если вы все еще «учите себя Python»!

    Это определяет декоратор для этого:

     def count_calls(fn): def _counting(*args, **kwargs): _counting.calls += 1 return fn(*args, **kwargs) _counting.calls = 0 return _counting @count_calls def foo(x): return x def bar(y): foo(y) foo(y) bar(1) print foo.calls 

    После вашего ответа – вот путь с фабрикой декораторов …

     import inspect def make_decorators(): # Mutable shared storage... caller_L = [] callee_L = [] called_count = [0] def caller_decorator(caller): caller_L.append(caller) def counting_caller(*args, **kwargs): # Returning result here separate from the count report in case # the result needs to be used... result = caller(*args, **kwargs) print callee_L[0].__name__, \ 'was called', called_count[0], 'times' called_count[0] = 0 return result return counting_caller def callee_decorator(callee): callee_L.append(callee) def counting_callee(*args, **kwargs): # Next two lines are an alternative to # sys._getframe(1).f_code.co_name mentioned by Ned... current_frame = inspect.currentframe() caller_name = inspect.getouterframes(current_frame)[1][3] if caller_name == caller_L[0].__name__: called_count[0] += 1 return callee(*args, **kwargs) return counting_callee return caller_decorator, callee_decorator caller_decorator, callee_decorator = make_decorators() @callee_decorator def foo(z): #do something return ' foo result' @caller_decorator def bar(x,y): # complicated algorithm/logic simulation... for i in xrange(x+y): foo(i) foobar = 'some result other than the call count that you might use' return foobar bar(1,1) bar(1,2) bar(2,2) 

    И вот результат (протестирован с Python 2.5.2):

     foo was called 2 times foo was called 3 times foo was called 4 times 
    Python - лучший язык программирования в мире.