在函数中更改 python 对象类型

Change python object type in a function

我的应用程序中有一个功能,如下所示:

def get_firebase_user(session: Session, firebase_user: FirebaseUser) -> users.User | None:
    if some_condition:
        return user_instance 

我有一个具有基本功能的实用程序模块,所以我决定将在模型为 None 时抛出异常的函数放入该模块中。它看起来像:

def throw_none_exception(inst, detail: str) -> None:
    """Throm exception with given detail if instance is None."""
    if inst is None:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=detail,
        )

整个问题都在我的 linter 中。如果我们用第一个函数声明模型并用第二个函数引发错误。在这种工作方式下,linter 无法检测模型如何变化,因此代码如下:

user = get_firebase_user(session, firebase_user)
throw_none_exception(user, "Such user doesn't exists")
if user.id == some_random_id:
    return 'You are the luckiest person i\'ve ever seen'

它returns我错了

Item "None" of "Optional[User]" has no attribute "id"

这很烦人:) 我怎样才能重新声明这个模型的类型?或者如何设法用另一种方式做到这一点,这样 linter 就不会出错?

这是一种定义 throw_none_exception 的方法,它可以将 inst 转换为 non-Optional 类型:

from typing import TypeVar, Optional

_T = TypeVar("_T")

def throw_none_exception(inst: Optional[_T], detail: str) -> _T:
    """Throw exception with given detail if instance is None."""
    if inst is None:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=detail,
        )
    return inst

现在如果你这样做:

user = throw_none_exception(
    get_firebase_user(session, firebase_user),
    "Such user doesn't exists"
)

user 将具有 non-Optional 类型,您应该能够访问 user.id 而不会出现类型检查错误。

这里的问题是如果 user 不是 None,linter 无法弄清楚 throw_none_exception 只有 returns。你只需要给 linter 一个提示。 assert 是执行此操作的标准方法。

throw_none_exception(user, "Such user doesn't exist")
assert user is not None
if user.id == some_random_id:
    ...

即使你 运行 Python 使用 -o 标志,所有 assert 语句都将被编译出来,但你的 linter 仍然会得到满足,因为它是静态依赖的可用信息。