Python mypy在方法参数为Union类型时标记错误



我有这些python类:

class LocalWritable(typing.TypedDict):
file_name: str

class GSheetWritable(typing.TypedDict):
tab_name: str

class S3Writable(typing.TypedDict):
data_name: str
table_name: str

WriterMeta = typing.Union[GSheetWritable, S3Writable, LocalWritable]
class DataWriter(ABC):
"""Defines the interface for all data writers"""
@abstractmethod
def write(self, data: pd.DataFrame, meta: WriterMeta, versionize: bool):
"""This method performs the writing of 'data'.
Every class implementing this method must implement its writing
using 'connector'
"""
pass
class GSheetOutputWriter(DataWriter):
def write(self, data: pd.DataFrame, meta: WriterMeta, versionize: bool):
data = data.replace({np.nan: 0, np.Inf: "Inf"})
print("Writing '{}' table to gsheet.".format(meta["tab_name"]))
if self.new:
tab = self.connector.get_worksheet(self.target.url, "Sheet1")
self.connector.rename_worksheet(tab, meta["tab_name"])
self.new = False
else:
tab = self.connector.add_worksheet(
self.target, meta["tab_name"], rows=1, cols=1
)
time.sleep(random.randint(30, 60))
self.connector.update_worksheet(
tab, [data.columns.values.tolist()] + data.values.tolist()
)

问题是在使用python mypy检查时使用write()方法。,因为它标记了这个错误:

cost_reporteroutputs__init__.py:209: error: TypedDict "S3Writable" has no key "tab_name"
cost_reporteroutputs__init__.py:209: note: Did you mean "table_name" or "data_name"?
cost_reporteroutputs__init__.py:209: error: TypedDict "LocalWritable" has no key "tab_name"

我要做的是在抽象类DataWriter的基础上实现三个具体类,每个类都实现自己的write()方法,每个类都接收WriterMetaunion的一个数据类型。我遇到的问题是python mypy根据三种数据类型(而不是其中任何一种)验证代码。

我该怎么做呢?

编辑

如果我将参数meta的类型更改为GsheetWritable(这是三种联合类型之一,也是这个具体类所期望的类型),mypy标记此错误:

cost_reporteroutputs__init__.py:202: error: Argument 2 of "write" is incompatible with supertype "DataWriter"; supertype defines the argument type as "Union[GSheetWritable, S3Writable, LocalWritable]"
cost_reporteroutputs__init__.py:202: note: This violates the Liskov substitution principle

Union的工作原理类似于集合论中的并集。换句话说,由多个类型组成的Union是一种只支持共享的的类型。

为了使用特定类型的属性(或任何东西),您需要向mymyy暗示您正在约束实例。可以通过将Union强制转换为特定类型,assert将对象指定为任何特定类型,以及其他方式来实现这一点。文档列出了缩小类型的方法。

import typing
from abc import ABC, abstractmethod
class LocalWritable(typing.TypedDict):
file_name: str

class GSheetWritable(typing.TypedDict):
tab_name: str

class S3Writable(typing.TypedDict):
data_name: str
table_name: str

WriterMeta = typing.Union[GSheetWritable, S3Writable, LocalWritable]

class DataWriter(ABC):
@abstractmethod
def write(self, data: str, meta: WriterMeta):
pass

class GSheetOutputWriter(DataWriter):
def write(self, data: str, meta: WriterMeta):
# LOOK HERE! The cast hints to mypy that meta is a GSheetWritable.
meta_cast: GSheetWritable = typing.cast(GSheetWritable, meta)
print("Writing '{}' table to gsheet.".format(meta_cast["tab_name"]))

进一步阅读

  • 类型窄化
  • 联合类型

相关内容

最新更新