Добавьте сам подписанный сертификат к Доверенным корневым центрам сертификации Локального компьютера
, можно импортировать сертификат путем выполнения MMC как, Администратор.
Если функция, к которой вы стремитесь, не делает что-то особенное, чтобы отметить «один экземпляр меня активен в стеке» (IOW: если функция является нетронутой и неприкасаемой и не может быть знайте об этой вашей особой потребности), нет никакой мыслимой альтернативы переходу от кадра к кадру вверх по стеку, пока вы не достигнете вершины (а функции там нет) или кадра стека для интересующей вас функции. Как показывают несколько комментариев к вопросу, крайне сомнительно, что стоит стремиться к оптимизации. Но, предположив ради аргумента, что это было стоящим ...:
Изменить : исходный ответ (OP) содержал много дефектов, но некоторые с тех пор были исправлены, поэтому Я' функция может находиться в стеке несколько раз (прямая или косвенная рекурсия). Нам явно нужен «мульти-набор» (также известный как «мешок»), структура, подобная множеству, которая отслеживает, «сколько раз» каждый элемент присутствует. В Python естественная реализация мультимножества - это dict, отображающая ключи в счетчики, что, в свою очередь, наиболее удобно реализовать как collections.defaultdict (int)
.
В-четвертых, общий подход должен быть threadsafe (по крайней мере, если это можно сделать легко ;-). К счастью, threading.local
делает его тривиальным, когда это применимо - и здесь, безусловно, должно быть (каждый стек имеет свой собственный отдельный поток вызовов).
В-пятых, затронутый интересный вопрос в некоторых комментариях (замечая, насколько плохо предлагаемые декораторы в некоторых ответах играют с другими декораторами: декоратор мониторинга, по-видимому, должен быть ПОСЛЕДНИМ (самым внешним), иначе проверка прервется. Это происходит из-за естественного, но неудачного выбора использования самого функционального объекта в качестве ключа к мониторингу.
Я предлагаю решить эту проблему другим выбором ключа: заставить декоратор взять (скажем, строку) аргумент идентификатора
, который должен быть уникальным (в каждом заданном потоке) и использовать идентификатор в качестве ключа в слове мониторинга. Код, проверяющий стек, конечно, должен знать идентификатор и также использовать его.
Во время декорирования декоратор может проверить свойство уникальности (используя отдельный набор). Идентификатор может быть оставлен по умолчанию для имени функции (так что это явно требуется только для сохранения гибкости мониторинга одноименных функций в том же пространстве имен); от свойства уникальности можно явным образом отказаться, когда несколько отслеживаемых функций должны считаться «одинаковыми» для целей мониторинга (это может иметь место, если данный оператор def
предназначен для выполнения несколько раз в немного разных контекстах создать несколько функциональных объектов, которые программисты хотят рассматривать как «одну и ту же функцию» для целей мониторинга). Наконец, должна быть возможность при желании вернуться к «объекту функции как идентификатору» в тех редких случаях, когда дальнейшее оформление ИЗВЕСТНО, что невозможно (поскольку в таких случаях это может быть самый удобный способ гарантировать уникальность)
. объединив все эти соображения, мы могли бы иметь (включая служебную функцию threadlocal_var
, которая, вероятно, уже будет в модуле панели инструментов, конечно; -) что-то вроде следующего ...:
import collections
import functools
import threading
threadlocal = threading.local()
def threadlocal_var(varname, factory, *a, **k):
v = getattr(threadlocal, varname, None)
if v is None:
v = factory(*a, **k)
setattr(threadlocal, varname, v)
return v
def monitoring(identifier=None, unique=True, use_function=False):
def inner(f):
assert (not use_function) or (identifier is None)
if identifier is None:
if use_function:
identifier = f
else:
identifier = f.__name__
if unique:
monitored = threadlocal_var('uniques', set)
if identifier in monitored:
raise ValueError('Duplicate monitoring identifier %r' % identifier)
monitored.add(identifier)
counts = threadlocal_var('counts', collections.defaultdict, int)
@functools.wraps(f)
def wrapper(*a, **k):
counts[identifier] += 1
try:
return f(*a, **k)
finally:
counts[identifier] -= 1
return wrapper
return inner
Я не тестировал этот код, поэтому он может содержать опечатку и т.п., но я предлагаю его, потому что надеюсь, что он охватывает все важные технические моменты, которые я объяснил выше .
Это все того стоит? Вероятно, нет, как объяснялось ранее. Однако я думаю, что «если это вообще стоит делать, то стоит делать правильно»; -).
Мне не очень нравится этот подход, но вот исправленная версия того, что вы делали:
from collections import defaultdict
import threading
functions_on_stack = threading.local()
def record_function_on_stack(f):
def wrapped(*args, **kwargs):
if not getattr(functions_on_stack, "stacks", None):
functions_on_stack.stacks = defaultdict(int)
functions_on_stack.stacks[wrapped] += 1
try:
result = f(*args, **kwargs)
finally:
functions_on_stack.stacks[wrapped] -= 1
if functions_on_stack.stacks[wrapped] == 0:
del functions_on_stack.stacks[wrapped]
return result
wrapped.orig_func = f
return wrapped
def function_is_on_stack(f):
return f in functions_on_stack.stacks
def nested():
if function_is_on_stack(test):
print "nested"
@record_function_on_stack
def test():
nested()
test()
Это обрабатывает рекурсию, многопоточность и исключения.
Я не нравится этот подход по двум причинам:
Лучшим подходом было бы проверить стек напрямую (возможно, как собственное расширение для скорости), и если возможно, найти способ кэшировать результаты на время жизни кадра стека. (Я не уверен, что это