首页 > 解决方案 > Mypy Optional dict 错误,预期类型不是可选的

问题描述

我有一个__init__能够从三个不同路径构建正确对象的函数。由于某些参数可以重复使用,因此它们在顶级 init 中具有默认值。

我不确定如何告诉 mypy 给定的参数在顶级 init 函数中是可选的,并且对于给定的正确路径是必需的。

common_record.py:138: error: Argument 1 to "_init_from_common_record" of "CommonRecord" has incompatible type "Optional[Dict[Any, Any]]"; expected "Dict[Any, Any]"
common_record.py:142: error: Argument 1 to "_init_from_raw_data" of "CommonRecord" has incompatible type "Optional[Dict[Any, Any]]"; expected "Dict[Any, Any]"
Makefile:74: recipe for target 'type-check' failed
make: *** [type-check] Error 1
class CommonRecord:
    """A Common Record type. This is a json serializable object that contains
    sections for required and known fields that are common among data sources.
    """
    def __init__(
            self,
            record: Dict = None,
            raw_record: Dict = None,
            *,
            system: System = None,
            domain: Domain = None) -> None:
        """Initialization for the Common Record Class

        Three valid creation cases:
            * A single dictionary indicating a dictionary that's of the Common
            Record type
            * A normalized record and a raw record that will be turned into a
            Common Record.
            * A System object, a Domain object, and a raw record dictionary.
        """
        if not raw_record:
            self._init_from_common_record(record)
        elif (system and domain and raw_record):
            self._init_from_objects(system, domain, raw_record)
        else:
            self._init_from_raw_data(record, raw_record)

初始化函数的签名是

def _init_from_raw_data(self, record: Dict, raw_record: Dict) -> None:
  def _init_from_objects(
            self,
            system: System,
            domain: Domain,
            raw_record: Dict) -> None:
def _init_from_common_record(self, common_record: Dict) -> None:

标签: python-3.xmypy

解决方案


您可以采取三种不同的方法。

首先,您可以修改条件以明确检查 if recordis None 并执行以下操作。

if not raw_record and not record:
    self._init_from_common_record(record)
elif (system and domain and raw_record):
    self._init_from_objects(system, domain, raw_record)
elif not record:
    self._init_from_raw_data(record, raw_record)
else:
    # Raise an exception here or something

其次,您可以添加检查以确保record不是无的断言。

if not raw_record:
    assert record is not None
    self._init_from_common_record(record)
elif (system and domain and raw_record):
    self._init_from_objects(system, domain, raw_record)
else:
    assert record is not None
    self._init_from_raw_data(record, raw_record)

第三种解决方案是转换record为正确的类型并完全跳过检查。不过我不推荐这种方法——验证你的对象是否被正确使用将是更强大的事情。


您还可以进行的一项额外但有些不相关的改进是使用重载改进构造函数的签名——基本上为每个构造 CommonRecord 的方法创建一个重载。这将有助于验证您是否始终正确地构造对象并“教”mypy 如何验证我们在上面在类型检查时所做的一些运行时检查。

但是,如果您希望您的实际实现正确进行类型检查,您仍然需要执行上面建议的三种方法之一。


您还可以做的另一件事是通过将两个私有初始化方法转换为静态方法来完全回避这个问题,这些方法将构造并返回一个新的CommonRecord.

这将使您有可能简化构造函数并帮助您使类型更精确。当然,主要的缺点是实例化一个新的 CommonRecord 现在变得稍微笨重了。


推荐阅读