Computed Signal API¶
reaktiv.Computed(func=None, /, *, equal=None)
¶
Create a computed signal that derives its value from other signals.
Can be used as a function or as a decorator (with or without parameters).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Optional[Callable[[], T]]
|
The computation function (when used as factory or decorator without params) |
None
|
equal
|
Optional[Callable[[T, T], bool]]
|
Optional custom equality function for change detection |
None
|
Returns:
| Type | Description |
|---|---|
Union[ComputeSignal[T], Callable[[Callable[[], T]], ComputeSignal[T]]]
|
A ComputeSignal instance or a decorator function |
Examples:
As a function:
from reaktiv import Signal, Computed
x = Signal(10)
result = Computed(lambda: x() * 2)
print(result()) # 20
As a decorator (no parameters):
from reaktiv import Signal, Computed
price = Signal(100)
quantity = Signal(2)
@Computed
def total():
return price() * quantity()
print(total()) # 200
As a decorator (with custom equality):
reaktiv.ComputeSignal
¶
A computed signal that derives its value from other signals.
ComputeSignal automatically tracks dependencies on other signals and recomputes its value when any dependency changes. Computations are lazy and cached - they only run when accessed and dependencies have changed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compute_fn
|
Callable[[], T]
|
A function that computes the signal's value from other signals |
required |
equal
|
Optional[Callable[[T, T], bool]]
|
Optional custom equality function for change detection |
None
|
Examples:
Basic computed signal:
from reaktiv import Signal, Computed
first_name = Signal("John")
last_name = Signal("Doe")
# Create computed signal
full_name = Computed(lambda: f"{first_name()} {last_name()}")
print(full_name()) # "John Doe"
first_name.set("Jane")
print(full_name()) # "Jane Doe"
Lazy computation:
from reaktiv import Signal, Computed
x = Signal(10)
y = Signal(20)
def expensive_computation():
print("Computing...")
return x() * y()
result = Computed(expensive_computation)
# Nothing happens yet - computation is lazy
# First access - computation runs
print(result()) # Prints: "Computing..." then "200"
# Second access - no computation (cached)
print(result()) # Just prints "200"
# Change a dependency
x.set(5)
# Next access will recompute
print(result()) # Prints: "Computing..." then "100"
Decorator pattern:
from reaktiv import Signal, Computed
price = Signal(100)
quantity = Signal(2)
@Computed
def total():
return price() * quantity()
print(total()) # 200
Error handling:
from reaktiv import Signal, Computed
x = Signal(10)
# Computed signal with potential error
result = Computed(lambda: 100 / x())
print(result()) # 10.0 (100 / 10)
# Set x to 0, causing division by zero
x.set(0)
# Exception is propagated to caller
try:
print(result())
except ZeroDivisionError as e:
print(f"Error: {e}")
# After fixing, computation works again
x.set(5)
print(result()) # 20.0 (100 / 5)
Note
Computed signals are lazy - they only compute when accessed and cache the result until dependencies change. When a computation raises an exception, it is propagated to the caller for flexible error handling.