【亲测免费】 干货满满:Dry Python 的 Returns 项目常见问题解答
2026-01-29 12:26:01作者:魏侃纯Zoe
还在为 Python 代码中的异常处理、None 值检查和依赖注入而烦恼吗?Dry Python 的 Returns 项目为你提供了一套完整的函数式编程解决方案!本文整理了 Returns 项目中最常见的 20+ 个问题,帮你快速上手这个强大的工具库。
📚 读完本文你能得到
- ✅ Returns 核心容器的使用场景和区别
- ✅ 常见错误模式和最佳实践解决方案
- ✅ 类型安全编程的完整指南
- ✅ 异步代码处理的最佳方式
- ✅ 依赖注入的优雅实现方案
🎯 核心容器选择指南
| 容器类型 | 适用场景 | 错误处理 | 纯度 |
|---|---|---|---|
Maybe |
处理 None 值 |
无错误,只有存在/不存在 | 纯函数 |
Result |
可能失败的操作 | 成功/失败两种状态 | 纯函数 |
IO |
不失败的副作用操作 | 无错误 | 不纯函数 |
IOResult |
可能失败的副作用操作 | 成功/失败两种状态 | 不纯函数 |
Future |
异步操作(不失败) | 无错误 | 不纯函数 |
FutureResult |
可能失败的异步操作 | 成功/失败两种状态 | 不纯函数 |
❓ 常见问题解答
1. 什么时候该用 Maybe,什么时候该用 Optional?
问题场景:你需要在代码中处理可能为 None 的值。
# ❌ 传统方式 - 嵌套的 if 判断
def get_street_address(order: Order) -> Optional[str]:
if order.user is not None:
if order.user.address is not None:
return order.user.address.street
return None
# ✅ Returns 方式 - 声明式链式调用
from returns.maybe import Maybe
def get_street_address(order: Order) -> Maybe[str]:
return Maybe.from_optional(order.user).bind_optional(
lambda user: user.address,
).bind_optional(
lambda address: address.street,
)
解答:使用 Maybe 当你想用函数式的方式处理 None,避免嵌套的 if 判断。Optional 更适合简单的类型注解。
2. Result 和异常处理有什么区别?
问题场景:你需要处理可能失败的操作。
# ❌ 异常方式 - 破坏执行流程
def fetch_user(user_id: int) -> User:
response = requests.get(f'/api/users/{user_id}')
response.raise_for_status() # 可能抛出异常
return response.json()
# ✅ Result 方式 - 显式错误处理
from returns.result import Result, safe
from returns.pipeline import flow
from returns.pointfree import bind
@safe
def _make_request(user_id: int) -> requests.Response:
response = requests.get(f'/api/users/{user_id}')
response.raise_for_status()
return response
@safe
def _parse_json(response: requests.Response) -> User:
return response.json()
def fetch_user(user_id: int) -> Result[User, Exception]:
return flow(user_id, _make_request, bind(_parse_json))
解答:Result 将错误作为值返回,而不是抛出异常,使错误处理成为类型系统的一部分。
3. 如何区分 IO 和 IOResult?
问题场景:你需要标记副作用操作。
flowchart TD
A[操作类型判断] --> B{操作是否可能失败?}
B -->|否| C{操作是否有副作用?}
B -->|是| D{操作是否有副作用?}
C -->|否| E[使用纯函数]
C -->|是| F[使用 IO 容器]
D -->|是| G[使用 IOResult 容器]
# 不失败但有副作用的操作 - 使用 IO
from returns.io import IO, impure
import random
@impure
def get_random_number() -> int:
return random.randint(1, 10) # 有副作用但不失败
# 可能失败且有副作用的操作 - 使用 IOResult
from returns.io import IOResultE, impure_safe
import requests
@impure_safe
def http_request(url: str) -> requests.Response:
response = requests.get(url)
response.raise_for_status() # 可能失败
return response
4. 如何处理异步代码?
问题场景:你需要混合同步和异步代码。
# ❌ 传统方式 - 到处都是 await
async def process_user(user_id: int) -> bool:
user = await fetch_user(user_id)
permissions = await get_user_permissions(user)
return await check_permissions(permissions)
# ✅ Returns 方式 - 声明式组合
from returns.future import FutureResultE, future_safe
@future_safe
async def fetch_user(user_id: int) -> User: ...
@future_safe
async def get_user_permissions(user: User) -> Permissions: ...
@future_safe
async def check_permissions(perms: Permissions) -> bool: ...
def process_user(user_id: int) -> FutureResultE[bool]:
return fetch_user(user_id).bind(
get_user_permissions
).bind(
check_permissions
)
5. 依赖注入的最佳实践
问题场景:你需要传递配置或依赖。
from returns.context import RequiresContext
from typing import Protocol
class Dependencies(Protocol):
database_url: str
api_timeout: int
def get_user_data(user_id: int) -> RequiresContext[UserData, Dependencies]:
return RequiresContext(lambda deps: _fetch_from_db(user_id, deps))
def _fetch_from_db(user_id: int, deps: Dependencies) -> UserData:
# 使用 deps.database_url 和 deps.api_timeout
return query_database(user_id, deps.database_url, deps.api_timeout)
# 使用
dependencies = SomeDependenciesClass()
result = get_user_data(123)(dependencies)
🛠️ 实用技巧和模式
6. 容器转换指南
flowchart LR
A[Maybe] -->|maybe_to_result| B[Result]
B -->|result_to_maybe| A
C[Result] -->|IOResult.from_result| D[IOResult]
D -->|unsafe_perform_io| E[实际值]
F[FutureResult] -->|awaitable| G[IOResult]
7. 错误类型组合
当需要组合不同错误类型时,使用 unify 而不是 bind:
from returns.result import Result, Success, Failure
from returns.pointfree import unify
def operation_a() -> Result[int, ValueError]: ...
def operation_b(arg: int) -> Result[str, IOError]: ...
result: Result[int, ValueError] = Success(1)
final_result = unify(operation_b)(result)
# 类型: Result[str, Union[ValueError, IOError]]
8. 模式匹配(Python 3.10+)
from returns.result import Success, Failure
def handle_result(result: Result[int, str]) -> str:
match result:
case Success(value):
return f"Success: {value}"
case Failure(error):
return f"Error: {error}"
📊 性能考量
| 操作 | 开销 | 建议 |
|---|---|---|
| 容器创建 | 低 | 可大量使用 |
| 链式调用 | 中 | 避免过深的链 |
| 异步操作 | 取决于事件循环 | 合理使用 |
| 类型检查 | 编译时 | 强烈推荐使用 mypy |
🚀 最佳实践总结
- 优先使用纯函数:尽可能将逻辑保持在纯函数中
- 显式标记副作用:使用
IO和IOResult明确标识不纯操作 - 错误作为值:用
Result代替异常进行错误处理 - 类型安全第一:充分利用 mypy 进行类型检查
- 渐进式采用:可以从部分模块开始使用,逐步推广
🔧 工具链配置
确保正确配置 mypy 插件:
# setup.cfg
[mypy]
plugins = returns.contrib.mypy.returns_plugin
strict = True
[mypy-returns.*]
ignore_missing_imports = True
🎉 结语
Returns 项目为 Python 开发者提供了一套完整的函数式编程工具,通过类型安全的容器和组合操作,帮助你编写更健壮、更易维护的代码。本文解答的常见问题覆盖了日常开发中的大多数场景,希望能为你的编程之旅提供帮助!
记得在实际项目中循序渐进地采用这些模式,根据具体需求选择合适的容器和组合方式。Happy coding!
登录后查看全文
项目优选
收起
deepin linux kernel
C
27
11
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
514
3.69 K
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
873
538
Ascend Extension for PyTorch
Python
316
360
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
333
152
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
1.31 K
732
暂无简介
Dart
757
182
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
12
1
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Java
67
20
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
1.05 K
519