Show HN: Reactive Signals for Python – inspired by Angular's reactivity model

github.com

17 points by buibuibui 7 hours ago

Hey everyone, I built reaktiv, a small reactive signals library for Python, inspired by Angular’s reactivity model. It lets you define Signals, Computed Values, and Effects that automatically track dependencies and update efficiently. The main focus is async-first reactivity without external dependencies.

Here is an example code:

``` import asyncio from reaktiv import Signal, ComputeSignal, Effect

async def main(): count = Signal(0) doubled = ComputeSignal(lambda: count.get() * 2)

    async def log_count():
        print(f"Count: {count.get()}, Doubled: {doubled.get()}")

    Effect(log_count).schedule()
    count.set(5)  # Triggers: "Count: 5, Doubled: 10"
    await asyncio.sleep(0)  # Allow effects to process
asyncio.run(main()) ```
fermigier 4 hours ago

Cool (probably), but it's not clear what it does or how useful it is when one doesn't know anything about Angular signals. Could you explain?

Also, care to compare to RxPY? (https://github.com/ReactiveX/RxPY)

  • buibuibui 4 hours ago

    Haha, I actually used RxPY a lot in the past! Back when I was more into Angular/RxJS and less familiar with Python, I thought I could apply the same concurrency patterns using RxPY. But I burned myself pretty badly. RxPY is powerful, but it’s also complex, and getting it to play nicely with asyncio (especially with typing) was frustrating enough that I eventually moved away from it.

    RxPY is a full reactive programming toolkit with observables, operators, and complex stream processing, while Signals are a more lightweight and declarative way to track state dependencies. RxPY is great for handling event streams, but for simple state management and reactive updates, Signals are much easier to reason about.

philote 6 hours ago

For those of use that haven't use Angular, can you explain what this is doing? And what's it do that we can't already do with asyncio? Also, it's weird you have to call `asyncio.sleep(0)`. Seems like you should be able to `await count.set(5)`.

I did look at the repo, but I couldn't easily understand the use case and what exactly it's doing from examples alone.

  • buibuibui 5 hours ago

    I’ve seen how the frontend world solved state management with reactivity, but I couldn’t find anything similar for backend development in Python. So I built reaktiv to bring the same automatic dependency tracking and state propagation to async Python code.

    In frontend frameworks, Signals eliminate the need for manual subscriptions and event handling, making state updates more efficient. I wanted the same benefits for backend systems where changes to shared state should propagate automatically, without polling, callbacks, or race conditions.

    For example, if a config value or cached result updates, anything depending on it should react immediately. With Signals, you don’t have to manually notify consumers or keep track of what depends on what. It just works (hopefully).

    About `asyncio.sleep(0)`: it’s just there to keep the example concise. Normally, you’d be inside an async function that naturally yields control, like handling a request or waiting for I/O.

jitl 5 hours ago

What kinds of Python programs would benefit from Signals? Most of the Python I've written is either small CLI tools that run to completion, or boring web servers using frameworks like Django that are request-response oriented, which also has a "run-to-completion" model for a request's handler code.

Also, I looked at your implementation, and your ComputedSignal implementation is not sound - it can give inconsistent results with respect to the input signals depending on the ordering of reads when you have a ComputedSignal that depends on other ComputedSignal.

  • buibuibui 4 hours ago

    In my case, I’ve built Python applications that poll multiple sensor data, perform calculations, and push results to the frontend. The frontend is also allowed to configure the measurements on the fly, so I needed some form of reactivity in my backend to handle dynamic changes smoothly.

    Could you share an example of the problem you’re referring to?