**kwargs 中具有多种类型的类型注释

Type annotation with multiple types in **kwargs

我正在尝试使用 Python 的 type annotations 和摘要 class。 我的 __init__ 函数如下所示:

from abc import ABCMeta

class SomeClass(object, metaclass=ABCMeta):
    def __init__(self, *args, **kwargs):
        print("Initiating %s object.", self.__class__.__name__)

        self.username = kwargs['data']
        assert isinstance(self.username, str)

        is_premioum = kwargs.get('premioum', False)

        self.money_investmant = kwargs.get('investmant')
        if isinstance(self.money_investmant, str):
            self.money_investmant = float(self.money_investmant)

如您所见,kwargs 可以包含多种类型的参数 - floatboolstr

现在,我正在尝试为函数编写类型注释,如下所示:

def __init__(self, *args, **kwargs: Union[bool, str, float]) -> None:

但是我的 PyCharm IDE 提醒我:

Except type 'Integral', got 'str' instead

并且:

Cannot find referance 'get' in bool | str | float'

我是不是做错了什么?

如果 kwargs 包含来自多个类型的参数,我应该如何编写类型注释?

请参阅 PyCharm 的问题跟踪器上的 this bug and this bug。这显然是 PyCharm 的检查器的问题; mypy(Python 的另一个类型检查器) 在我执行类似代码时不会抱怨

已经有针对此问题的修复程序,而且显然可用 in build 171.2014.23。在那之前,我认为 Any 足以作为让检查员停止抱怨的临时解决方法。

如果想要描述 kwargs 中预期的特定命名参数,可以改为传入定义必需参数和可选参数的 TypedDict。可选参数是什么 kwargs:

这允许取消设置(不是 None 默认值)可选参数并对其进行类型提示。

如果它们的键具有无效的 python 变量名,这也很有用,因为除了非常通用的 **kwargs 值类型提示之外,TypedDict 是定义这些值类型的唯一方法。

import typing
from abc import ABCMeta


class RequiredProps(typing.TypedDict):
    # all of these must be present
    data: str

class OptionalProps(typing.TypedDict, total=False):
    # these can be included or they can be omitted
    premium: bool
    investment: typing.Union[str, float]

class ReqAndOptional(RequiredProps, OptionalProps):
    pass

class SomeClass(object, metaclass=ABCMeta):
    def __init__(self, *args, kwargs: ReqAndOptional):
        print("Initiating %s object.", self.__class__.__name__)

        self.username = kwargs['data']
        assert isinstance(self.username, str)

        is_premium = kwargs.get('premium', False)
        assert isinstance(is_premium, bool)

        self.money_investment = kwargs.get('investment')
        assert isinstance(elf.money_investment, (str, float))
        if isinstance(self.money_investment, str):
            self.money_investment = float(self.money_investment)