Equivalent feature to Rust ? operator
johnthagen opened this issue · 3 comments
btw, this library is super cool
I was trying out Result
and one of the first things I wanted to do to get familiar with the Python version was to implement something similar from Rust.
This Rust by Example example shows how the ?
operator does early return in an ergonomic way.
fn op_(x: f64, y: f64) -> MathResult {
// if `div` "fails", then `DivisionByZero` will be `return`ed
let ratio = div(x, y)?;
// if `ln` "fails", then `NonPositiveLogarithm` will be `return`ed
let ln = ln(ratio)?;
sqrt(ln)
}
Now, this is a Rust language feature which might be hard to emulate in Python, but I was curious if returns
has something similar. Perhaps along the lines of the deprecated try!
macro?
What is the best way to handle this situation? Is match
ing on each intermediate Result
the best way?
You can do something like (pseudo-code):
def reraise(func: Callable[_P, _R]) -> Callable[_P, ResultE[_R]]:
def inner(*args: _P.args, **kwargs) -> ResultE[_R]:
try:
return Success(func(*args, **kwargs))
except UnwrapFailedError as exc:
return Failure(exc.inner_exception)
@reraise
def logic() -> int:
return a().unwrap() + b.unwrap()
def a() -> ResultE[int]:
return 1
def b() -> ResultE[int]:
return 2
I also just discovered that flow
is an ergonomic way to handle at least some early return issues (where there is a single value flowing through without side effects):
class MathError(Enum):
DivisionByZero = auto()
NonPositiveLogarithm = auto()
MathResult: TypeAlias = Result[float, MathError]
def div(x: float, y: float) -> MathResult:
if y == 0.0:
return Failure(MathError.DivisionByZero)
return Success(x / y)
def ln(x: float) -> MathResult:
if x <= 0.0:
return Failure(MathError.NonPositiveLogarithm)
return Success(math.log(x))
def op_flow(x: float, y: float) -> MathResult:
return flow(
div(x, y),
bind(ln),
)
Since this was more of a question, I will go ahead and close this issue to keep the tracker clean.
Maybe one day Python will add something like ?
😄