
本文介绍两种专业、可扩展的方式,让函数能接受用户 id 或用户名中的任意一种(而非强制两者)来标识用户,避免冗余参数和运行时校验混乱。
本文介绍两种专业、可扩展的方式,让函数能接受用户 id 或用户名中的任意一种(而非强制两者)来标识用户,避免冗余参数和运行时校验混乱。
在实际开发中,常遇到类似场景:一个用户可通过唯一 ID(如 int)或用户名(如 str)识别,二者互为补充、无需同时提供。但若将 first_id, first_username, second_id, second_username 全部设为独立参数,不仅接口臃肿,还易引发调用歧义(如同时传 id 和 username 且不一致)或遗漏校验(如两者皆未传)。理想方案应保证:每个用户身份仅需提供 ID 或用户名之一,且类型安全、语义清晰、易于维护。
✅ 方案一:统一参数类型 + 运行时类型分发(轻量级推荐)
适用于逻辑简单、依赖少的场景。将每个用户抽象为单一参数,类型为 Union[int, str],内部根据类型自动解析:
from typing import Union
def get_chat(first_user: Union[int, str], second_user: Union[int, str]) -> dict:
"""
获取两个用户之间的聊天会话。
:param first_user: 用户1的ID(int)或用户名(str)
:param second_user: 用户2的ID(int)或用户名(str)
"""
def resolve_user(user: Union[int, str]) -> tuple[int, str]:
if isinstance(user, int):
user_id = user
user_name = _fetch_username_by_id(user_id) # 假设已实现
elif isinstance(user, str):
user_name = user
user_id = _fetch_id_by_username(user_name) # 假设已实现
else:
raise TypeError(f"Invalid user type: {type(user).__name__}. Expected int or str.")
return user_id, user_name
first_id, first_name = resolve_user(first_user)
second_id, second_name = resolve_user(second_user)
# 实际业务逻辑(例如查询数据库)
return {
"chat_id": f"{min(first_id, second_id)}_{max(first_id, second_id)}",
"participants": [first_name, second_name]
}⚠️ 注意事项:
- 必须确保 _fetch_* 函数具备幂等性与容错能力(如用户名不存在时抛出明确异常);
- 不建议在函数内硬编码 ID/username 映射逻辑,应封装为独立服务层方法;
- 若 ID 与 username 类型可能重叠(如用户名为纯数字字符串),需额外校验避免歧义。
✅ 方案二:面向对象建模(工业级推荐)
当系统中“用户身份”概念频繁复用(如用于消息、权限、通知等多处),强烈推荐引入 User 实体类,实现构造器重载与单点数据源管理:
from typing import Union, TYPE_CHECKING
if TYPE_CHECKING:
from typing import Self
class User:
def __init__(self, user_id: int, username: str) -> None:
self.id = user_id
self.username = username
@classmethod
def from_id(cls, user_id: int) -> 'User':
username = _fetch_username_by_id(user_id)
return cls(user_id, username)
@classmethod
def from_username(cls, username: str) -> 'User':
user_id = _fetch_id_by_username(username)
return cls(user_id, username)
def get_chat(first_user: User, second_user: User) -> dict:
"""参数即契约:传入即代表已验证有效用户身份"""
return {
"chat_id": f"{min(first_user.id, second_user.id)}_{max(first_user.id, second_user.id)}",
"participants": [first_user.username, second_user.username],
"user_objects": [first_user, second_user] # 可直接复用实例
}
# 调用示例(清晰、安全、IDE 友好):
# chat = get_chat(User.from_id(123), User.from_username("alice"))
# chat = get_chat(User.from_username("bob"), User.from_id(456))✅ 优势总结:
- 类型安全:User 实例天然携带完整身份信息,杜绝参数缺失或冲突;
- 职责分离:身份解析逻辑集中于 User 类,业务函数专注核心逻辑;
- 可测试性强:User.from_id() 等方法可独立单元测试,get_chat 可用 mock User 实例快速验证;
- 扩展友好:后续增加邮箱、UUID 等新标识方式,只需新增 from_email() 类方法,无需修改 get_chat 签名。
无论选择哪种方案,核心原则是:将“身份识别”这一领域概念显式建模,而非退化为松散的原始参数集合。这不仅能提升 API 的健壮性与可读性,更是迈向清晰领域驱动设计(DDD)的重要一步。

















