What is Blinker? In short, Blinker is a “small broadcasting” system in Python. You can think of it as a signal tower where various modules and plugins in your code can send messages by throwing a signal to the tower; any place that wants to receive messages just needs to attach the corresponding listener, and as soon as the signal arrives, it will be received immediately. It does not require hard binding between them, making it completely loosely coupled, which is particularly convenient when writing plugins or frameworks.
What pain points does it solve?
| Pain Point | Traditional Method | Benefits of Blinker |
| High code coupling | Directly calling functions/global variables | Decouples through signals, where senders and receivers do not know each other |
| Complex multi-module communication | Manually maintaining callback lists or global event centers | Automatically manages signal registration and weak reference recycling |
| Difficult to debug/test | Business logic mixed together | <span>muted()</span> and <span>receivers</span> properties make it easy to check and mute |
| Multi-thread safety issues | Manually writing locks or queues | Blinker is thread-safe, eliminating the hassle of locks |
How to install and use it?
pip install blinker
After installation, the basic usage process consists of three steps:
- 1. Create a signal:
<span>signal('event_name')</span>, with the same name being globally unique. - 2. Subscribe:
<span>signal('event_name').connect(callback_function, sender=specific_object)</span>(optional sender restriction). - 3. Send:
<span>signal('event_name').send(sender, key1=val1, key2=val2)</span>.
Tip: If you only want to compute time-consuming data when there are receivers, first check
<span>if signal('event_name').receivers:</span>before<span>send()</span>, to avoid wasting resources.
Here’s a common example, the code can almost run directly:
from blinker import signal
# 1️⃣ Create a signal
round_started = signal('round-started')
# 2️⃣ Subscribe
def log_round(round_no):
print(f'Round {round_no} has started!')
round_started.connect(log_round)
def special_for_two(round_no):
print('This round is special 2!')
round_started.connect(special_for_two, sender=2)
# 3️⃣ Send
for i in range(1, 4):
round_started.send(i)
Output:
Round 1 has started!
Round 2 has started!
This round is special 2!
Round 3 has started!
Overview of Advantages and Disadvantages
| Advantages | Description |
| Extremely simple API | <span>signal</span>, <span>connect</span>, <span>send</span> three core functions, learnable in a few minutes |
| Automatic weak references | Receiver functions no longer leak memory, GC can reclaim them automatically |
| Supports anonymous signals | <span>Signal()</span> directly generates a unique signal, suitable for internal temporary events |
| Thread-safe | Can be used safely in multi-threaded environments |
| Can collect return values | <span>send()</span> returns the return values of each receiver, facilitating result aggregation |
| Supports async | <span>send_async()</span> + <span>connect_via</span> allows asynchronous functions to join as well |
| Disadvantages | Description |
| Relatively single function | Only responsible for signal dispatching, complex scheduling scenarios still need to be implemented manually |
| Documentation is not rich enough | Official examples are somewhat concise, and in-depth usage often requires self-exploration |
| When relying on weak references, local functions may be prematurely GC’d | Need to pay attention to the lifecycle of closures or local functions |
Conclusion If you are writing Flask plugins, Django extensions, or even pure scripts, you often encounter the need for “who notifies whom”. Blinker moves this to the signal level with just a few lines of code, making the code cleaner and the modules more independent. Its lightweight, thread-safe, and automatic weak reference features help you avoid many headaches from “unexpected references” or “lock contention” during development. Although it does not provide advanced scheduling itself, as an “event bus” it is already powerful enough to build a highly maintainable system combined with your business logic.
Project Address: https://github.com/pallets-eco/blinker