Melhor resposta
Com base nos comentários acima, aqui está uma estratégia geral. Obviamente, os detalhes importam muito, é claro .
Basicamente, você terá duas partes.
O objeto de evento ou o “ editor” é responsável por mantendo uma lista de todas as funções que devem ser chamadas quando um evento acontece. Ele tem um método fire()
que percorre essa lista e chama todas as funções sucessivamente. Provavelmente também deve ter métodos para gerenciar a lista (removendo uma função da lista que não é mais necessária).
Os manipuladores ou “ assinantes” são funções que você vai chamar quando o evento realmente acontecer. A única coisa complicada é que você precisa controlar a assinatura dos manipuladores para que o evento possa chamá-los sem fazer nenhuma introspecção extra.
Aqui está um exemplo ultramínimo:
class Event(object):
def \_\_init\_\_(self, *args):
self.handlers = set()
self.args = args
def add(self, fn):
self.handlers.add(fn)
def remove(self, fn):
self.handlers.remove(fn)
def \_\_call\_\_(self, *args):
"""fire the event -- uses \_\_call\_\_ so we can just invoke the object directly..."""
runtime\_args = self.args + args
for each\_handler in self.handlers:
each\_handler(*runtime\_args)
class ExampleObject(object):
"""publish start and stop events"""
def \_\_init\_\_(self):
self.start = Event("started")
self.stop = Event("stopped")
def example\_handler(*args):
""" reacts to an event"""
print "example handler fired", args
fred = ExampleObject()
fred.start.add(example\_handler)
fred.stop.add(example\_handler)
fred.start()
fred.stop("optional extra arg")
Isso deve produzir
example handler fired ("started",)
example handler fired ("stopped", "optional extra arg")
Os principais problemas de gerenciamento são:
Tratamento de exceções. você precisa decidir se o manipulador deve ser seguro para exceções ou não. Se não, o código acima está mais ou menos OK, mas se você não quer que um assinante ruim desative todo o programa, você precisa decidir como lidar com uma exceção e se deve ou não “cancelar a assinatura” do manipulador infrator .
Gerenciamento de memória. O exemplo usa apenas uma função como um manipulador; a menos que você del () a função, você não precisa gerencie sua vida útil. No entanto, você frequentemente desejará ter objetos que podem ser chamados ou funções de membro como manipuladores / assinantes. Em caso afirmativo, você provavelmente precisará usar referências fracas em vez do conjunto ingênuo usado no exemplo – caso contrário, os manipuladores de eventos acabarão mantendo os objetos vivos depois que eles deveriam ter saído do escopo e deveriam ser coletados como lixo.
Metadados: o exemplo inclui um pouco de metadados – a string que é passada como Event()
s são declarados. Seu aplicativo pode precisar de mais ou menos do que isso. Mais metadados geralmente significam mais acoplamento, o que não é o ideal. No entanto, se todos os seus gerenciadores tiverem a assinatura (*args, **kwargs)
, você sempre pode passar os dados e decidir no nível do gerenciador se você se importa com isso ou não.
Boa referência : O padrão do observador em Python
Exemplo da ideia básica em ação: teodoxo / mGui
Resposta
Se você for ao site da estrutura da web do tornado, há uma página de exemplos. Nessa página, há um exemplo de código de aplicativo de bate-papo. É extremamente curto e compreensível.