如何强制转换类型的字典以避免分配中的不兼容类型

How to force cast typed dicts to avoid Incompatible types in assignment

我正在尝试在不使用 NotRequired 的情况下以高效功能(尽量避免复制)执行以下操作(简化示例)(原因如下所示):

Mytd1 = TypedDict("Mytd1", {a: NotRequired[str], x: int})
Mytd_extra = TypedDict("Mytd_extra", {a: str, x: int, z: str})


def foo(y: Mytd1) -> Mytd_extra:
    # users input object should NOT contain z
    y = cast(Mytd_extra, y). # fails - my guess is `a` is the offender
    y["z"] = "hooray"
    if "a" not in y:
        y["a"] = "whatever"
    return y
 

Mypy 抱怨转换为“赋值中的不兼容类型”,但这是我想要做的。我如何实现这一目标?我认为 a 是违规者 - 输出类型需要它

想要:

# kill Mytd1 
Mytd_extra = TypedDict("Mytd_extra", {x: int, z: NotRequired[str]})

因为这将允许客户端将 {x: 5, z: "asdf"} 传递到 foo 但应该禁止 - 他们只允许传递 {x: 5}.

我认为以下是可行的,但我试图避免它以提高效率,因为此函数被多次调用:

def foo(y: Mytd1) -> Mytd_extra:
    new_var: Mytd_extra = {k: v for k:v in y.items()}
    new_var["z"] = "ohno"
    return new_var

你至少有两个完全有效的解决方案(假设 python 3.11 不理会 typing vs typing_extensions,如果需要调整你的导入)。问题是 y 的类型是 Mytd1,所以你不能给它赋值 Mytd_extra(强制转换的结果)。

使用另一个变量

from typing import TypedDict, NotRequired, cast

Mytd1 = TypedDict("Mytd1", {'a': NotRequired[str], 'x': int})
Mytd_extra = TypedDict("Mytd_extra", {'a': str, 'x': int, 'z': str})


def foo(orig_y: Mytd1) -> Mytd_extra:
    # users input object should NOT contain z
    y = cast(Mytd_extra, orig_y)
    y["z"] = "hooray"
    if "a" not in y:
        y["a"] = "whatever"
    return y

这是a playground这个解决方案。

允许重新定义(mypy 标志)

保留您的原始代码,但 运行 带有 --allow-redefinition(或将 allow_redefinition = true 添加到您使用的配置文件):playground.

警告: allow_redefinition 没有 Super Cow Powers,它的用例仅限于一个场景:分配给 pre-defined 变量,当RHS 中的表达式包含此变量。它允许以下内容:

y = 'abc'
y = list(y)

但不是这个:

y = 'abc'
y = 1