Skip to content

Commit 10b6f7a

Browse files
committed
🦄 refactor(result): 优化类型安全与性能
- 为 Ok/Err 的 dataclass 添加 `slots=True`,降低内存开销 - 将 `Ok.unwrap_err()` 与 `Err.expect()` 返回类型标注为 `NoReturn`,明确其始终抛出异常的行为 - 引入 `ParamSpec`,使 `catch` 装饰器与 `try_catch` 函数完美保留原函数参数签名 - 统一注释描述,将“Rust 风格”更新为“辅助构造器”
1 parent fed66c0 commit 10b6f7a

3 files changed

Lines changed: 86 additions & 85 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "nonone"
3-
version = "0.1.6"
3+
version = "0.1.7"
44
description = "A modern, lightweight Rust-style Result type for Python 3.10+ pattern matching."
55
readme = "README.md"
66
authors = [

src/nonone/result.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
from __future__ import annotations
22
from dataclasses import dataclass
3-
from typing import Generic, TypeVar, Callable, Any, TypeAlias
3+
from typing import Generic, TypeVar, Callable, Any, TypeAlias, NoReturn, ParamSpec
44
import functools
55

66
T = TypeVar("T")
77
E = TypeVar("E")
88
U = TypeVar("U")
99
F = TypeVar("F")
10+
P = ParamSpec("P") # 用于保留装饰器参数签名
1011

1112

1213
class UnwrapError(RuntimeError):
1314
"""统一抛出的解包异常。"""
1415

1516

1617
# -------------------- 成功分支 --------------------
17-
@dataclass(frozen=True)
18+
@dataclass(frozen=True, slots=True)
1819
class Ok(Generic[T, E]):
1920
value: T
2021

@@ -27,7 +28,7 @@ def is_err(self) -> bool:
2728
def unwrap(self) -> T:
2829
return self.value
2930

30-
def unwrap_err(self) -> E:
31+
def unwrap_err(self) -> NoReturn:
3132
raise UnwrapError(f"Called unwrap_err() on an Ok: {self.value!r}")
3233

3334
def unwrap_or(self, default: T) -> T:
@@ -61,7 +62,7 @@ def or_else(self, f: Callable[[E], Result[T, F]]) -> Result[T, F]:
6162

6263

6364
# -------------------- 失败分支 --------------------
64-
@dataclass(frozen=True)
65+
@dataclass(frozen=True, slots=True)
6566
class Err(Generic[T, E]):
6667
error: E
6768

@@ -83,7 +84,7 @@ def unwrap_or(self, default: T) -> T:
8384
def unwrap_or_else(self, op: Callable[[E], T]) -> T:
8485
return op(self.error)
8586

86-
def expect(self, msg: str) -> T:
87+
def expect(self, msg: str) -> NoReturn:
8788
raise UnwrapError(f"{msg}: {self.error!r}")
8889

8990
def map(self, f: Callable[[T], U]) -> Err[U, E]:
@@ -111,7 +112,7 @@ def inspect(self, func: Callable[[E], Any]) -> Err[T, E]:
111112
Result: TypeAlias = Ok[T, E] | Err[T, E]
112113

113114

114-
# -------------------- 小写构造器(Rust 风格) --------------------
115+
# -------------------- 辅助构造器 --------------------
115116
def ok(value: T) -> Ok[T, Any]:
116117
"""小写构造器,返回 Ok[T, Any](错误类型留作 Any)。"""
117118
return Ok(value)
@@ -123,13 +124,13 @@ def err(error: E) -> Err[Any, E]:
123124

124125

125126
# -------------------- 装饰器:将普通函数变为返回 Result 的函数 --------------------
126-
def catch(func: Callable[..., T]) -> Callable[..., Result[T, Exception]]:
127+
def catch(func: Callable[P, T]) -> Callable[P, Result[T, Exception]]:
127128
"""
128-
装饰器。自动捕获函数内部的异常,
129-
将正常返回值包装为 Ok(value),异常包装为 Err(exception)
129+
装饰器。自动捕获异常并返回 Result。
130+
利用 ParamSpec 完美保留了原函数的参数类型提示
130131
"""
131132
@functools.wraps(func)
132-
def wrapper(*args: Any, **kwargs: Any) -> Result[T, Exception]:
133+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> Result[T, Exception]:
133134
try:
134135
return Ok(func(*args, **kwargs))
135136
except Exception as e:
@@ -138,7 +139,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Result[T, Exception]:
138139

139140

140141
# -------------------- 函数式调用:立即执行函数并返回 Result --------------------
141-
def try_catch(func: Callable[..., T], *args: Any, **kwargs: Any) -> Result[T, Exception]:
142+
def try_catch(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> Result[T, Exception]:
142143
"""手动调用:立即执行函数并返回 Result。"""
143144
try:
144145
return Ok(func(*args, **kwargs))

0 commit comments

Comments
 (0)