Найти - Пользователи
Полная версия: События, цепочка обработчиков, как проверить наличие обработчика?
Начало » Python для новичков » События, цепочка обработчиков, как проверить наличие обработчика?
1
ctocopok
Есть проект, в котором реализована работа с events. Типов событий довольно много, и каждое событие может иметь цепочку обработчиков.
Благодаря переопределению __iadd__ , обработчики добавляются очень просто: Event += newhandler

У меня есть возможность редактировать код лишь некоторых обработчиков событий, и я хочу добавить вызов своих процедур/функций к другим событиям.

В том месте кода, где я имею возможность править исходник, я написал:
def myHandler():
print "now i got a machine gun!"

targetEvent += myHandler
дело сделано, myHandler вызывается при каждом срабатывании targetEvent, но… так как редактируемый мною обработчик в котором я добавляю свой хэндлер, вызывается несколько раз, получается, что у targetEvent вырастает список обработчиков, делающих одно и то же.
targetEvent.__repr__ дает такую картину:
set([
<function myHandler at 0x0FE3F230>,
<function myHandler at 0x12122DF0>,
<function myHandler at 0x0FE3FEB0>,
<function myHandler at 0x0FE3FEF0>,
...еще много раз ...
<function myHandler at 0x0FE12370>])
пробовал конструкцию
if myHandler in targetEvent._eventHandlers_:
pass
else:
targetEvent += myHandler
где targetEvent._eventHandlers_ это набор обработчиков, но меня это не выручило, очевидно, потому что myHandler к моменту этой проверки уже определен по другому адресу.
Можно, конечно, сделать проверку через поиск подстроки с именем функции в str(targetEvent._eventHandlers_), благо myHandler - это мною управляемое имя, и я могу его сделать уникальным, но, наверное, есть способ проще и изящнее?

Простите, если сумбурно.
bw
> так как редактируемый мною обработчик в котором я добавляю свой хэндлер, вызывается несколько раз,
> получается, что у targetEvent вырастает список обработчиков

Как так получается я не понял. Зачем переопределять одну и ту же функцию, делающую одно и то же и подписывать на одно и тоже событие? Это, кстати, ещё и умудриться надо:
for i in range(5):
def handler():
print 'я дурак'
myevent += handler
> +=
Дурной знак. Придумай и используй свои методы с читаемыми именами, например subscribeHandler или registerHandler.

p.s. Можно попробовать различать методы по их именам и именам модулей в которых они определены. Но это плохой способ. Вообще, если есть вероятность многократной подписки на одно и тоже событие обработчика, который должен быть подписан только раз, то что то в коде не так, и желаемая проверка это плохой способ справить с проблемой.

..bw
ctocopok
Дело в том, что другого способа у меня нет. Только из нескольких событий, которые могут вызываться несколько раз в течение работы программы, соответственно, надо иметь проверки на уникальность.
bw
Пример в студию.
И не кусок вырвиглазного кода, а нормальный, модуль или пакет. Такой что бы работал и претензии были только по твоей теме.

А по сути:
>> так как редактируемый мною обработчик в котором я добавляю свой хэндлер, вызывается несколько раз,
>> получается, что у targetEvent вырастает список обработчиков
> Как так получается я не понял. Зачем переопределять одну и ту же функцию, делающую одно и то же и
> подписывать на одно и тоже событие?
> Вообще, если есть вероятность многократной подписки на одно и тоже событие обработчика, который
> должен быть подписан только раз, то что то в коде не так, и желаемая проверка это плохой способ справить
> с проблемой.
Никаких объяснений и возражений не последовало, так что я вряд ли в силе помочь, не мой, похоже, уровень.

..bw
Ed
Тут трудно что-либо сказать не зная как реализован __iadd__ у targetEvent. Можете показать код или хотя бы рассказать как это сделано? По сути нужно либо сделать так, чтобы сам __iadd__ не добавлял, либо не добавлять, поняв, что targetEvent уже содержит наш обработчик. В обоих случаях нужны хоть какие-то сведения о targetEvent. Пока вы их не дадите вам никто не поможет.
ctocopok
вот реализация event-ов.
class Event(object):
def __init__(self, manager=None):
self._Event__delegates = set()
if manager is not None:
manager.register(self)
return None

def __call__(self, *args):
except:
LOG_CURRENT_EXCEPTION()
continue
for delegate in set(self._Event__delegates):
delegate(*args)
continue

def __iadd__(self, delegate):
self._Event__delegates.add(delegate)
return self

def __isub__(self, delegate):
self._Event__delegates.discard(delegate)
return self

def clear(self):
self._Event__delegates.clear()
т.е. ничего необычного.

в проекте сотни модулей, причем, несколько из них реализованы в .exe-файле, куда также встроен интерпретатор python (то есть, даже не отдельной dll, как иногда бывает), и к этим модулям тоже есть отсылки. Из-за этого, запустить модули отдельно, без .exe, не представляется возможным. Можно только в некоторые события “влезть”.

Пока что, на стадии установки своего “хука” я делаю так:
if str(repr(targetEvent._Event__delegates)).find('myHandler')>-1:
#хук уже есть
pass
else:
targetEvent += myHandler
возможно, определение myHandler тоже надо поместить в ветку “else”, дабы не плодить функции, которые даже не будут использоваться.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB