Python Rusty Result Library: 在Python中使用Rust风格的Result类型
Project description
PyRsult
Python Rusty Result Library:在 Python 中使用 Rust 风格的
Result和Option类型。
版本:0.4.0 | GitHub
安装
pip install git+https://github.com/fexcode/pyrsult.git
快速上手
from pyrsult import Result, Option
# Result:要么成功,要么失败
def div(a: int, b: int) -> Result[float, str]:
if b == 0:
return Result.Failure("divide by zero")
return Result.Success(a / b)
r = div(10, 2)
print(r.unwrap()) # 5.0
print(r.map(lambda x: x * 2)) # Success(10.0)
# Option:要么有值,要么空
def find(lst, target):
for v in lst:
if v == target:
return Option.Some(v)
return Option.Nothing()
find([1, 2, 3], 2).map(lambda x: x * 10).unwrap_or(0) # 20
Result 详解
Result[T, E] 是一个泛型联合类型,有两个分支:
Success[T]— 操作成功,携带值TFailure[E]— 操作失败,携带错误E
构造
Result.Success(value) # → Success(value)
Result.Failure(error) # → Failure(error)
Success 和 Failure 也可直接用作构造器(也支持 match 模式匹配)。
判别
is_ok() -> bool
判断当前值是否是 Success。
Result.Success(42).is_ok() # True
Result.Failure("err").is_ok() # False
is_err() -> bool
判断当前值是否是 Failure。
Result.Failure("err").is_err() # True
Result.Success(42).is_err() # False
取值
unwrap() -> T
取出 Success 内部的值。如果当前是 Failure,则抛出 ValueError。
Result.Success(42).unwrap() # 42
Result.Failure("bad").unwrap() # ValueError: Unwrap failed | bad
unwrap_err() -> E
取出 Failure 内部的错误值。如果当前是 Success,则抛出 ValueError。
Result.Failure("bad").unwrap_err() # 'bad'
Result.Success(42).unwrap_err() # ValueError: Called unwrap_err on an Ok value
unwrap_or(default: T) -> T
取出 Success 内部的值;如果是 Failure,则返回 default。
Result.Failure("bad").unwrap_or(0) # 0
Result.Success(42).unwrap_or(0) # 42
unwrap_or_else(func: Callable[[E], T]) -> T
取出 Success 内部的值;如果是 Failure,则将错误传入 func 并返回其结果(懒求值)。
Result.Failure("bad").unwrap_or_else(lambda e: len(e)) # 3
Result.Success(42).unwrap_or_else(lambda e: 0) # 42
expect(msg: str) -> T
取出 Success 内部的值;如果是 Failure,则抛出 ValueError,异常消息为 msg。
Result.Success(42).expect("custom") # 42
Result.Failure("bad").expect("custom") # ValueError: custom
变换
map(func: Callable[[T], U]) -> Result[U, E]
如果当前是 Success,对其内部值应用 func 并返回新的 Success;Failure 保持不变。
Result.Success(10).map(lambda x: x * 2) # Success(20)
Result.Failure("bad").map(lambda x: x) # Failure('bad')
map_err(func: Callable[[E], F]) -> Result[T, F]
如果当前是 Failure,对其内部错误应用 func 并返回新的 Failure;Success 保持不变。
Result.Failure("bad").map_err(str.upper) # Failure('BAD')
Result.Success(42).map_err(str.upper) # Success(42)
链式
and_then(func: Callable[[T], Result[U, E]]) -> Result[U, E]
如果当前是 Success,则将内部值传入 func(func 必须返回 Result),实现扁平化链式调用。类似 Rust 的 and_then / flat_map。Failure 保持不变。
def safe_div(x: float) -> Result[float, str]:
return Result.Failure("zero") if x == 0 else Result.Success(10 / x)
Result.Success(2.0).and_then(safe_div) # Success(5.0)
Result.Success(0.0).and_then(safe_div) # Failure('zero')
Result.Failure("err").and_then(safe_div) # Failure('err')
or_else(func: Callable[[E], Result[T, F]]) -> Result[T, F]
如果当前是 Failure,则将错误传入 func 进行补救;Success 保持不变。
def补救(e: str) -> Result[int, str]:
return Result.Success(42)
Result.Failure("bad").or_else(补救) # Success(42)
Result.Success(10).or_else(补救) # Success(10)
模式匹配
Python 3.10+ 支持直接对 Result 进行 match:
match div(10, 0):
case Success(v):
print("ok", v)
case Failure(e):
print("err", e) # err divide by zero
Option 详解
Option[T] 用于表示一个值可能存在也可能不存在,有两个分支:
Some[T]— 值存在Nothing— 值为空
构造
Option.Some(value) # → Some(value)
Option.Nothing() # → Nothing
Option.From(value) # value 不为 None → Some(value),否则 → Nothing()
Some 和 Nothing 也可直接使用。
判别
is_some: bool(属性)
判断是否为 Some。
Option.Some(42).is_some # True
Option.Nothing().is_some # False
is_nothing: bool(属性)
判断是否为 Nothing。
Option.Nothing().is_nothing # True
Option.Some(42).is_nothing # False
取值
unwrap() -> T
取出 Some 内部的值。如果为 Nothing 则抛出 ValueError。
Option.Some(42).unwrap() # 42
Option.Nothing().unwrap() # ValueError: 这个值是 Nothing
unwrap_or(default: T) -> T
取出 Some 内部的值;Nothing 时返回 default。
Option.Nothing().unwrap_or(0) # 0
Option.Some(42).unwrap_or(0) # 42
unwrap_or_else(func: Callable[[], T]) -> T
取出 Some 内部的值;Nothing 时调用 func 并返回其结果(懒求值)。
Option.Nothing().unwrap_or_else(lambda: 99) # 99
Option.Some(42).unwrap_or_else(lambda: 99) # 42
变换
map(func: Callable[[T], U]) -> Option[U]
如果为 Some,对内部值应用 func 并返回新的 Some;Nothing 保持不变。
Option.Some(7).map(lambda x: x * 2) # Some(14)
Option.Nothing().map(lambda x: x) # Nothing
map_or(default: U, func: Callable[[T], U]) -> U
map + unwrap_or 的组合:Some 时应用 func,Nothing 时返回 default。
Option.Some(7).map_or(0, lambda x: x * 2) # 14
Option.Nothing().map_or(0, lambda x: x * 2) # 0
map_or_else(default: Callable[[], U], func: Callable[[T], U]) -> U
map + unwrap_or_else 的组合,两个参数均为懒求值。
Option.Some(7).map_or_else(lambda: 0, lambda x: x * 2) # 14
Option.Nothing().map_or_else(lambda: 0, lambda x: x * 2) # 0
链式
and_then(func: Callable[[T], Option[U]]) -> Option[U]
如果为 Some,将内部值传入 func(func 必须返回 Option),实现扁平化链式调用。类似 Rust 的 and_then。
def parse_int(s: str) -> Option[int]:
try:
return Option.Some(int(s))
except ValueError:
return Option.Nothing()
Option.Some("42").and_then(parse_int) # Some(42)
Option.Some("abc").and_then(parse_int) # Nothing
Option.Nothing().and_then(parse_int) # Nothing
filter(predicate: Callable[[T], bool]) -> Option[T]
如果为 Some 且满足 predicate,则保留;否则变为 Nothing。
Option.Some(7).filter(lambda x: x > 5) # Some(7)
Option.Some(3).filter(lambda x: x > 5) # Nothing
Option.Nothing().filter(lambda x: x > 5) # Nothing
备选
or_(optb: Option[T]) -> Option[T]
当前为 Some 时返回自身,否则返回 optb。
Option.Some(1).or_(Option.Some(2)) # Some(1)
Option.Nothing().or_(Option.Some(2)) # Some(2)
or_else(func: Callable[[], Option[T]]) -> Option[T]
当前为 Some 时返回自身,否则调用 func 并返回其结果(懒求值)。
Option.Nothing().or_else(lambda: Option.Some(99)) # Some(99)
Option.Some(1).or_else(lambda: Option.Some(99)) # Some(1)
类型转换
ok_or(err: E) -> Union[T, E]
将 Option 转为"值或错误"风格:Some(v) → v,Nothing → err。
Option.Some(5).ok_or("empty") # 5
Option.Nothing().ok_or("empty") # 'empty'
迭代
iter() -> Iterator[T]
返回包含 0 或 1 个元素的迭代器,方便 for 循环。
for v in Option.Some(42).iter():
print(v) # 42
list(Option.Some(3).iter()) # [3]
list(Option.Nothing().iter()) # []
运算符
__bool__
Option 可直接用于布尔上下文。
if Option.Some(42):
print("有值") # 输出:有值
bool(Option.Nothing()) # False
bool(Option.Some(42)) # True
| 运算符
a | b 等价于 a.or_(b),取第一个非空值。
Option.Nothing() | Option.Some(3) # Some(3)
Option.Some(1) | Option.Some(2) # Some(1)
快捷属性
Sm -> Some[T]
当确定当前值一定是 Some 时,直接获取 Some 包装(而非内部值)。若实际为 Nothing 则抛出 ValueError。
Option.Some(5).Sm # Some(5)
NN -> T
iam_sure_this_value_is_not_nothing 的别名。当确定当前值一定不是 Nothing 时,直接取出内部值。若实际为 Nothing 则抛出 ValueError。用法同 unwrap() 但不抛 ValueError 的包装异常。
Option.Some(5).NN # 5
实战:读取配置
import os
from pyrsult import Result, Option
def env_int(key: str) -> Result[int, str]:
val = os.getenv(key)
return (
Option.From(val)
.map(int)
.ok_or(f"{key} not a valid int")
)
port = env_int("PORT").unwrap_or(8080)
欢迎 PR & Issue!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyrsult-0.5.0.tar.gz.
File metadata
- Download URL: pyrsult-0.5.0.tar.gz
- Upload date:
- Size: 7.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8718e6e5967f6a08dcff467b110804b8f064128475a095a81dcd24342a1cb4f7
|
|
| MD5 |
37904f727d302a59a552a8dc4b7df59d
|
|
| BLAKE2b-256 |
eae9bf5bbd8f2639dae2addc4672ff21c6022e06a63ac28a6a7366c1e9c84ce1
|
Provenance
The following attestation bundles were made for pyrsult-0.5.0.tar.gz:
Publisher:
python-publish.yml on fexcode/pyrsult
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyrsult-0.5.0.tar.gz -
Subject digest:
8718e6e5967f6a08dcff467b110804b8f064128475a095a81dcd24342a1cb4f7 - Sigstore transparency entry: 2009450303
- Sigstore integration time:
-
Permalink:
fexcode/pyrsult@84bdef7e6ecc9cffc9e39853fd989182970af47e -
Branch / Tag:
refs/heads/master - Owner: https://github.com/fexcode
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@84bdef7e6ecc9cffc9e39853fd989182970af47e -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyrsult-0.5.0-py3-none-any.whl.
File metadata
- Download URL: pyrsult-0.5.0-py3-none-any.whl
- Upload date:
- Size: 7.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
015094745ed41e44b045664c2ea5f8d7ae35d88be646bf48a5c578024f2d167e
|
|
| MD5 |
6ba138a94e34ad8beddfb32054256f61
|
|
| BLAKE2b-256 |
db0b6a6133b273e0cb4f790f9b58c142cef721948d52d15aa4d6c21df2bbc9ac
|
Provenance
The following attestation bundles were made for pyrsult-0.5.0-py3-none-any.whl:
Publisher:
python-publish.yml on fexcode/pyrsult
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyrsult-0.5.0-py3-none-any.whl -
Subject digest:
015094745ed41e44b045664c2ea5f8d7ae35d88be646bf48a5c578024f2d167e - Sigstore transparency entry: 2009450360
- Sigstore integration time:
-
Permalink:
fexcode/pyrsult@84bdef7e6ecc9cffc9e39853fd989182970af47e -
Branch / Tag:
refs/heads/master - Owner: https://github.com/fexcode
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@84bdef7e6ecc9cffc9e39853fd989182970af47e -
Trigger Event:
push
-
Statement type: