У меня есть приложение Python, в котором я хотел бы отслеживать количество вызовов функций в стандартном случайном модуле во время выполнения; есть ли хороший способ сделать это, или мне нужно «вручную» сделать это?Подсчет количества вызовов случайным в Python?
ответ
Мне кажется, что профилировщик Python должен иметь возможность сделать это «красиво». Посмотрите на a post about Python profiling on SO.
Во время работы кажется, что decorators - это путь. Конечно, случайный модуль по умолчанию не имеет декораторов, поэтому, возможно, вам нужно определить модуль monitoredrandom с декораторами, который проксирует случайный модуль и подсчитывает вызовы. Если вы сохраняете имена функций и подписи так же, как в случайном порядке, вам нужно изменить импорт в своем коде.
Сделайте функцию обертки, которая увеличивает счетчик, а затем выполняет вызов и возвращает результат.
Если вы считаете, что это «руководство», то да.
Вы можете также обезьяна патч 'random' модуль для замены функции с обертками, чтобы уменьшить влияние на кодовую базу. – millimoose
Вот грязный раствор:
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))
Этот код должен быть выполнен в самом начале программы (может быть в виде отдельного модуля), перед любым другим кодом, включая импорт.
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).
Редактировать: это полезно, только если вы хотите, чтобы счетчик был отключен, как указано в комментарии.
Лучшее, что я могу придумать, это проксирование - я не верю, что замена 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
с помощью этого метода дает мне отсчет шесть - так не совсем уверен, как там работают внутренности ....
+1 Для идеи. Если, конечно, им не нужен доступ к этой информации по какой-либо причине программно или во время выполнения (конечно, это была бы важная информация для включения в вопрос) – Levon
Действительно, мне нужно отслеживать это во время выполнения (я отредактировал исходный вопрос, чтобы отразить это). – adrianp
Спасибо за +1! Я бы заглянул в код профайлера, чтобы получить дополнительные идеи о том, как это сделать.Как только появился проект PyMonitor, который использовал сборщик мусора для мониторинга времени выполнения программ Python, но для того, чтобы это послужило вашей цели, требуется дальнейшее расследование. – jpe