[英]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 is: error: "BaseProduct" has no attribute "a_specific_id"
mypy 错误是:
error: "BaseProduct" has no attribute "a_specific_id"
How to annotate AProductRequestSubmitter.__call__
properly?如何正确注释
AProductRequestSubmitter.__call__
? This class is specific for AProduct
, there are other submitters for different product types.此 class 专用于
AProduct
,还有针对不同产品类型的其他提交者。
Is it possible to use Generic types or Literal values somehow?是否可以以某种方式使用通用类型或文字值? Or maybe cast or assert is an only way to go?
或者,强制转换或断言是 go 的唯一方法?
There are multiple ways to achieve what you are trying to, I will show the ones that pop out the top of my head right now.有多种方法可以实现您的目标,我将展示那些现在突然出现在我脑海中的方法。
There may be multiple children having BaseProduct
as their parent and there is no way for the type checker to know for sure, you will never pass a ProductSubmissionCommand
instance that has product
attribute of a type that is a child of BaseProduct
that does not have a_specific_id
attribute.可能有多个子级以
BaseProduct
作为其父级,并且类型检查器无法确定,您永远不会传递ProductSubmissionCommand
实例,该实例具有的product
属性类型是BaseProduct
的子级,但没有a_specific_id
属性. In order to make sure this can never happen, you could start your function call with a type assertion, such as:为了确保这永远不会发生,您可以使用类型断言开始您的 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 (or any other static type checker) should now be quiet, because the program will never reach the part of the code, where a_specific_id
is accessed unless the correct type is in use. Pycharm(或任何其他 static 类型检查器)现在应该是安静的,因为程序永远不会到达代码的一部分,除非使用了正确的类型,否则访问
a_specific_id
的部分。
ProductSubmissionCommand
ProductSubmissionCommand
If you really plan on using AProductRequestSubmitter
for instances, where ProductSubmissionCommand
has product
of type ProductA
, you may subclass your ProductSubmissionCommand
and typehint its product
attribute as a ProductA
instance.如果您确实打算将
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
Again, all clever typecheckers should now understand, that cmd
will always have product.a_specific_id
attribute.同样,所有聪明的类型检查器现在都应该明白,
cmd
将始终具有product.a_specific_id
属性。
Protocol
Protocol
Using:使用:
class ProductASubmissionCommand(Protocol):
product: ProductA
class AProductRequestSubmitter:
def __call__(self, job_id: int, cmd: ProductASubmissionCommand):
...
cmd.product.a_specific_id
You are basically saying "accept anything, that has an attribute named product
of a type ProductA
".您基本上是在说“接受任何具有名为
ProductA
类型的product
的属性”。 This is a little hacky and makes you create a protocol subclass only for the sake of typehinting this single method call, but, again, should work with all static type checkers.这有点 hacky,让您创建一个协议子类只是为了对这个单一的方法调用进行类型提示,但同样,它应该适用于所有 static 类型检查器。
You have 2 possible ways.你有两种可能的方法。
Ignore static typint by using an explicit getattr
call通过使用显式
getattr
调用忽略 static 类型
class AProductRequestSubmitter: def __call__(self, job_id: int, cmd: ProductSubmissionCommand): ... getattr(cmd.product, 'a_specific_id')
Use Generic
to specialize ProductSubmissionCommand
on a static typing point of view:使用
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.