Python 和 MyPy - 将 Kwargs 传递给复杂函数

rmo*_*hea 5 type-hinting python-3.5 mypy

考虑以下向函数parent和添加类型提示的尝试child

def parent(*, a: Type1, b: Type2):
    ...

def child(*, c: Type3, d: Type4, **kwargs):
    parent(**kwargs)
    ...
Run Code Online (Sandbox Code Playgroud)

MyPy抱怨说,kwargs有型Dict[str, Any],但该参数ab要求Type1,并Type2分别。

我了解解决此错误的方法是child按以下方式重写:

def child(*, a: Type1, b: Type2, c: Type3, d: Type4, **kwargs):
    parent(a=a, b=b)
    ...
Run Code Online (Sandbox Code Playgroud)

但是如果参数列表parent长,或有功能grandchild有其自身的参数列表和必须调用child。您是否需要从所有下游函数中枚举参数及其类型?或者是否有一种优雅的方式来处理**kwargs?

rmo*_*hea 0

随着PEP-692TypedDict的出现,这个问题在技术上得到了解决:

class ParentKwargs(TypedDict):
    a: Type1
    b: Type2

def parent(**kwargs: Unpack[ParentKwargs]):
    ...

class ChildKwargs(ParentKwargs):
    c: Type3
    d: Type4

def child(**kwargs: Unpack[ChildKwargs]):
    ...
Run Code Online (Sandbox Code Playgroud)

尽管可能不是完全理想的方式 - 您现在必须解构 kwargs 才能使用它们,并且处理默认值并不漂亮:

class ParentKwargs(TypedDict):
    a: Type1
    b: Type2

def parent(**kwargs: Unpack[ParentKwargs]):
    a = kwargs["a"]
    b = kwargs["b"]


class OptionalChildKwargs(TypedDict, total=False):
    c: Type3

class ChildKwargs(OptionalChildKwargs, ParentKwargs):
    d: Type4

def child(**kwargs: Unpack[ChildKwargs]):
    c = kwargs.get(default_value)
    d = kwargs["d"]
Run Code Online (Sandbox Code Playgroud)

此时,视觉噪音太多,最好枚举所有 kwargs,因为您需要缺席TypedDict