Pacotes PyPI
Em junho de 2020, esses são os pacotes relacionados ao evento disponíveis no PyPI, ordenados pela data de lançamento mais recente.
Tem mais
É possível escolher entre várias bibliotecas, usando terminologias muito diferentes (eventos, sinais, manipuladores, envio de métodos, ganchos, ...).
Estou tentando manter uma visão geral dos pacotes acima, além das técnicas mencionadas nas respostas aqui.
Primeiro, alguma terminologia ...
Padrão de observador
O estilo mais básico do sistema de eventos é o 'método bag of handler', que é uma implementação simples do padrão Observer .
Basicamente, os métodos do manipulador (chamadas) são armazenados em uma matriz e são chamados quando o evento é acionado.
Publicar-Assinar
A desvantagem dos sistemas de eventos do Observer é que você só pode registrar os manipuladores no objeto Event (ou lista de manipuladores) real. Portanto, no momento da inscrição, o evento já precisa existir.
É por isso que existe o segundo estilo de sistemas de eventos: o
padrão de publicação-assinatura . Aqui, os manipuladores não se registram em um objeto de evento (ou lista de manipuladores), mas em um distribuidor central. Os notificadores também conversam apenas com o despachante. O que ouvir ou o que publicar é determinado por 'sinal', que nada mais é do que um nome (string).
Padrão do mediador
Também pode ser interessante: o padrão do Mediador .
Hooks
Um sistema de 'gancho' é usado geralmente no contexto de plugins de aplicativos. O aplicativo contém pontos de integração fixos (ganchos), e cada plug-in pode se conectar a esse gancho e executar determinadas ações.
Outros eventos'
Nota: threading.Event não é um 'sistema de eventos' no sentido acima. É um sistema de sincronização de threads em que um thread aguarda até que outro thread 'sinalize' o objeto Event.
As bibliotecas de mensagens de rede geralmente também usam o termo 'eventos'; às vezes, esses conceitos são semelhantes; às vezes não. É claro que eles podem atravessar fronteiras de processos, processos e computadores. Veja, por exemplo
, pyzmq , pymq ,
Twisted , Tornado , gevent , eventlet .
Referências fracas
No Python, manter uma referência a um método ou objeto garante que ele não seja excluído pelo coletor de lixo. Isso pode ser desejável, mas também pode levar a vazamentos de memória: os manipuladores vinculados nunca são limpos.
Alguns sistemas de eventos usam referências fracas em vez de regulares para resolver isso.
Algumas palavras sobre as várias bibliotecas
Sistemas de eventos no estilo observador:
- O zope.event mostra o básico de como isso funciona (veja a resposta de Lennart ). Nota: este exemplo nem suporta argumentos do manipulador.
- A implementação da lista de chamadas do LongPoke mostra que esse sistema de eventos pode ser implementado de forma muito minimalista por subclassificação
list
.
- A variação de Felk EventHook também garante as assinaturas de callees e chamadores.
- O EventHook do spassig (padrão de evento de Michael Foord) é uma implementação direta.
- A aula de Josip's Valued Lessons Event é basicamente a mesma, mas usa um em
set
vez de um list
para armazenar a sacola e implementos __call__
que são adições razoáveis.
- O PyNotify é similar em conceito e também fornece conceitos adicionais de variáveis e condições ('evento alterado da variável'). A página inicial não está funcional.
- axel é basicamente um saco de manipuladores com mais recursos relacionados a rosqueamento, tratamento de erros, ...
- O python-dispatch exige que as classes de origem pares sejam derivadas
pydispatch.Dispatcher
.
- O buslane é baseado em classes, suporta manipuladores únicos ou múltiplos e facilita dicas de tipo extensas.
- O Observador / Evento do Pithikos é um design leve.
Bibliotecas de publicação / assinatura:
- O pisca - pisca possui alguns recursos interessantes, como desconexão automática e filtragem com base no remetente.
- O PyPubSub é um pacote estável e promete "recursos avançados que facilitam a depuração e manutenção de tópicos e mensagens".
- pymitter é uma porta Python do Node.js EventEmitter2 e oferece namespaces, curingas e TTL.
- O PyDispatcher parece enfatizar a flexibilidade em relação à publicação muitos-para-muitos etc. Suporta referências fracas.
- louie é um PyDispatcher reformulado e deve funcionar "em uma ampla variedade de contextos".
- O pypydispatcher é baseado no PyDispatcher (você adivinhou ...) e também funciona no PyPy.
- O django.dispatch é um PyDispatcher reescrito "com uma interface mais limitada, mas com maior desempenho".
- pyeventdispatcher é baseado no event-dispatcher da estrutura PHP do Symfony.
- O dispatcher foi extraído do django.dispatch, mas está ficando bastante antigo.
- O EventManger de Cristian Garcia é uma implementação muito curta.
Outras:
- O pluggy contém um sistema de gancho usado pelos
pytest
plugins.
- O RxPy3 implementa o padrão Observável e permite mesclar eventos, repetir etc.
- Os sinais e slots do Qt estão disponíveis no PyQt
ou PySide2 . Eles funcionam como retorno de chamada quando usados no mesmo encadeamento ou como eventos (usando um loop de eventos) entre dois encadeamentos diferentes. Sinais e Slots têm a limitação de que eles só funcionam em objetos de classes derivadas
QObject
.
Eu tenho feito desta maneira:
No entanto, como em tudo o que vi, não há pydoc gerado automaticamente para isso, nem assinaturas, o que é realmente péssimo.
fonte
_bag_of_handlers
que é uma lista. O método add da classe seria simplesmenteself._bag_of_handlers.append(some_callable)
. O método de disparo da classe passaria por _bag_of_handlers` passando os argumentos e kwargs fornecidos aos manipuladores e executaria cada um em sequência.Usamos um EventHook como sugerido por Michael Foord em seu Event Pattern :
Basta adicionar EventHooks às suas aulas com:
Adicionamos a funcionalidade para remover todos os ouvintes de um objeto à classe Michaels e terminamos com isso:
fonte
self.__handlers = [h for h in self._handlers if getattr(h, 'im_self', False) != obj]
Eu uso o zope.event . São os ossos mais vazios que você pode imaginar. :-) De fato, aqui está o código fonte completo:
Observe que você não pode enviar mensagens entre processos, por exemplo. Não é um sistema de mensagens, apenas um sistema de eventos, nada mais, nada menos.
fonte
Encontrei este pequeno script em Lições valorizadas . Parece ter a proporção certa de simplicidade / potência que eu estou procurando. Peter Thatcher é o autor do código a seguir (nenhum licenciamento é mencionado).
fonte
Aqui está um design minimalista que deve funcionar bem. O que você precisa fazer é simplesmente herdar
Observer
uma classe e depois usarobserve(event_name, callback_fn)
para escutar um evento específico. Sempre que esse evento específico for acionado em qualquer lugar do código (ou sejaEvent('USB connected')
), o retorno de chamada correspondente será acionado .Exemplo:
fonte
Eu criei uma
EventManager
classe (código no final). A sintaxe é a seguinte:Aqui está um exemplo:
Resultado:
Código EventManger:
fonte
Você pode dar uma olhada no pymitter ( pypi ). É uma abordagem pequena de arquivo único (~ 250 loc) "fornecendo namespaces, curingas e TTL".
Aqui está um exemplo básico:
fonte
Fiz uma variação da abordagem minimalista de Longpoke, que também garante as assinaturas de chamadas e chamadores:
fonte
Se eu codifico no pyQt eu uso o paradigma de soquetes / sinais QT, o mesmo é para django
Se eu estiver fazendo E / S assíncrona, use o módulo de seleção nativo
Se eu estiver usando um analisador python do SAX, estou usando a API de eventos fornecida pelo SAX. Parece que sou vítima da API subjacente :-)
Talvez você deva se perguntar o que você espera da estrutura / módulo de eventos. Minha preferência pessoal é usar o paradigma Socket / Signal do QT. mais informações sobre isso podem ser encontradas aqui
fonte
Aqui está outro módulo para consideração. Parece uma opção viável para aplicativos mais exigentes.
fonte
Se você quiser fazer coisas mais complicadas, como mesclar eventos ou tentar novamente, poderá usar o padrão Observable e uma biblioteca madura que implementa isso. https://github.com/ReactiveX/RxPY . Observáveis são muito comuns em Javascript e Java e muito convenientes para usar em algumas tarefas assíncronas.
SAÍDA :
fonte
Se você precisar de um eventbus que funcione através dos limites do processo ou da rede, poderá experimentar o PyMQ . Atualmente, ele suporta pub / sub, filas de mensagens e RPC síncrono. A versão padrão funciona em cima de um back-end do Redis, portanto, você precisa de um servidor Redis em execução. Há também um back-end na memória para teste. Você também pode escrever seu próprio back-end.
Para inicializar o sistema:
Isenção de responsabilidade: eu sou o autor desta biblioteca
fonte
Você pode tentar o
buslane
módulo.Essa biblioteca facilita a implementação do sistema baseado em mensagens. Ele suporta comandos (manipulador único) e abordagem de eventos (0 ou múltiplos manipuladores). O Buslane usa anotações do tipo Python para registrar corretamente o manipulador.
Exemplo simples:
Para instalar o buslane, basta usar o pip:
fonte
Algum tempo atrás, escrevi uma biblioteca que pode ser útil para você. Ele permite que você tenha ouvintes locais e globais, várias maneiras diferentes de registrá-los, prioridade de execução e assim por diante.
Dê uma olhada pyeventdispatcher
fonte