繁体   English   中英

在签名中注释特定的数据类子类

[英]Annotating specific dataclass subclass in a signature

from dataclasses import dataclass


@dataclass
class BaseProduct:
    ...


@dataclass
class ProductA(BaseProduct):
    a_specific_id: int


@dataclass
class ProductSubmissionCommand:
    product_id: str
    product: BaseProduct


class AProductRequestSubmitter:
    def __call__(self, job_id: int, cmd: ProductSubmissionCommand):
        ...
        cmd.product.a_specific_id

mypy 错误是: error: "BaseProduct" has no attribute "a_specific_id"

如何正确注释AProductRequestSubmitter.__call__ 此 class 专用于AProduct ,还有针对不同产品类型的其他提交者。

是否可以以某种方式使用通用类型或文字值? 或者,强制转换或断言是 go 的唯一方法?

有多种方法可以实现您的目标,我将展示那些现在突然出现在我脑海中的方法。

在运行时确保正确的类型

可能有多个子级以BaseProduct作为其父级,并且类型检查器无法确定,您永远不会传递ProductSubmissionCommand实例,该实例具有的product属性类型是BaseProduct的子级,但没有a_specific_id属性. 为了确保这永远不会发生,您可以使用类型断言开始您的 function 调用,例如:

class AProductRequestSubmitter:
    def __call__(self, job_id: int, cmd: ProductSubmissionCommand):
        if not isinstance(cmd.product, ProductA):
            raise TypeError(f"Only 'ProductA' instances are allowed, not '{cmd.product.__class__.__name__}'")
        ...
        cmd.product.a_specific_id

Pycharm(或任何其他 static 类型检查器)现在应该是安静的,因为程序永远不会到达代码的一部分,除非使用了正确的类型,否则访问a_specific_id的部分。

子类ProductSubmissionCommand

如果您确实打算将AProductRequestSubmitter用于实例,其中ProductSubmissionCommand具有ProductA类型的product ,您可以将您的ProductSubmissionCommand子类化并将其product属性类型提示为ProductA实例。

@dataclass
class ProductASubmissionCommand(ProductSubmissionCommand):
    product: ProductA


class AProductRequestSubmitter:
    def __call__(self, job_id: int, cmd: ProductASubmissionCommand):
        ...
        cmd.product.a_specific_id

同样,所有聪明的类型检查器现在都应该明白, cmd将始终具有product.a_specific_id属性。

使用Protocol

使用:

class ProductASubmissionCommand(Protocol):
    product: ProductA

class AProductRequestSubmitter:
    def __call__(self, job_id: int, cmd: ProductASubmissionCommand):
        ...
        cmd.product.a_specific_id

您基本上是在说“接受任何具有名为ProductA类型的product的属性”。 这有点 hacky,让您创建一个协议子类只是为了对这个单一的方法调用进行类型提示,但同样,它应该适用于所有 static 类型检查器。

你有两种可能的方法。

  1. 通过使用显式getattr调用忽略 static 类型

     class AProductRequestSubmitter: def __call__(self, job_id: int, cmd: ProductSubmissionCommand): ... getattr(cmd.product, 'a_specific_id')
  2. 使用Generic在 static 打字观点上专门ProductSubmissionCommand

     T = TypeVar("T", bound=BaseProduct) @dataclass class ProductSubmissionCommand(Generic[T]): product_id: str product: T class AProductRequestSubmitter: def __call__(self, job_id: int, cmd: ProductSubmissionCommand[ProductA]): pass

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM