2012-06-24 4 views
3

У меня есть приложение Python, в котором я хотел бы отслеживать количество вызовов функций в стандартном случайном модуле во время выполнения; есть ли хороший способ сделать это, или мне нужно «вручную» сделать это?Подсчет количества вызовов случайным в Python?

ответ

7

Мне кажется, что профилировщик Python должен иметь возможность сделать это «красиво». Посмотрите на a post about Python profiling on SO.

Во время работы кажется, что decorators - это путь. Конечно, случайный модуль по умолчанию не имеет декораторов, поэтому, возможно, вам нужно определить модуль monitoredrandom с декораторами, который проксирует случайный модуль и подсчитывает вызовы. Если вы сохраняете имена функций и подписи так же, как в случайном порядке, вам нужно изменить импорт в своем коде.

+0

+1 Для идеи. Если, конечно, им не нужен доступ к этой информации по какой-либо причине программно или во время выполнения (конечно, это была бы важная информация для включения в вопрос) – Levon

+0

Действительно, мне нужно отслеживать это во время выполнения (я отредактировал исходный вопрос, чтобы отразить это). – adrianp

+0

Спасибо за +1! Я бы заглянул в код профайлера, чтобы получить дополнительные идеи о том, как это сделать.Как только появился проект PyMonitor, который использовал сборщик мусора для мониторинга времени выполнения программ Python, но для того, чтобы это послужило вашей цели, требуется дальнейшее расследование. – jpe

3

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

Если вы считаете, что это «руководство», то да.

+1

Вы можете также обезьяна патч 'random' модуль для замены функции с обертками, чтобы уменьшить влияние на кодовую базу. – millimoose

4

Вот грязный раствор:

import functools 

def monitor(f): 
    @functools.wraps(f) 
    def decorated(*args, **kwargs): 
     print("{}: {}, {}".format(f.__name__, args, kwargs)) 
     # Do whatever you want: increment some counter, etc. 
     return f(*args, **kwargs) 
    return decorated 

import random 

for name in dir(random): 
    f = getattr(random, name) 
    if callable(f) and not name.startswith('_'): 
     setattr(random, name, monitor(f)) 

Этот код должен быть выполнен в самом начале программы (может быть в виде отдельного модуля), перед любым другим кодом, включая импорт.

1

cProfile возвращает количество вызовов в каждую функцию.

Что-то, как это должно работать:

import my_module 
import cProfile 

cProfile.run('my_module.my_func()') 

где my_module.my_func является точкой входа в программу. Это выводит следующее:

 7 function calls in 0.000 seconds 

Ordered by: standard name 

ncalls tottime percall cumtime percall filename:lineno(function) 
    1 0.000 0.000 0.000 0.000 <string>:1(<module>) 
    1 0.000 0.000 0.000 0.000 bar.py:4(bar) 
    1 0.000 0.000 0.000 0.000 foo.py:4(foo) 
    1 0.000 0.000 0.000 0.000 my_module.py:4(my_func) 
    1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
    2 0.000 0.000 0.000 0.000 {method 'random' of '_random.Random' objects} 

Последней строка показывает, что в целом были 2 вызовов к случайному методу (которые были в 2-х различных модулях в моем игрушечном например, foo.py и bar.py).

Редактировать: это полезно, только если вы хотите, чтобы счетчик был отключен, как указано в комментарии.

2

Лучшее, что я могу придумать, это проксирование - я не верю, что замена sys.modules может быть выполнена с помощью специального объекта dict-esque. Обратите внимание, я не люблю это, и на вашей голове и будет ...

class random(object): 
    def __init__(self): 
     from collections import defaultdict 
     import random as r_ 
     self.R = r_ 
     self.__lookups = defaultdict(int) 
     def __getattr__(self, name): 
      self.__lookups[name] += 1 
      return getattr(self.R, name) 
    @property 
    def freq(self): 
     return self.__lookups 

Ужасная ляп, но фактически прокси для стандартного модуля. Как вы попадаете в пространство имен, я действительно не уверен - возможно, поместил его в модуль, затем (теперь создавая имена) from random_testing import random вместо обычного import random.

я заметил, что работает два randint с помощью этого метода дает мне отсчет шесть - так не совсем уверен, как там работают внутренности ....

 Смежные вопросы

  • Нет связанных вопросов^_^