我正在创建一个自定义容器,它在切片时返回自身的一个实例:
from typing import Union, List
class CustomContainer:
def __init__(self, values: List[int]):
self.values = values
def __getitem__(self, item: Union[int, slice]) -> Union[int, CustomContainer]:
if isinstance(item, slice):
return CustomContainer(self.values[item])
return self.values[item]这是可行的,但附带以下问题:
a = CustomContainer([1, 2])
b = a[0] # is always int, but recognized as both int and CustomContainer
c = a[:] # is always CustomContainer, but recognized as both int and CustomContainer
# Non-scalable solution: Forced type hint
d: int = a[0]
e: CustomContainer = a[:]如果我将__getitem__的返回类型更改为int (我最初的方法),那么a[0]正确地显示了int类型,但是a[:]被认为是list而不是CustomContainer。据我所知,在python2中曾经有一个函数来定义如何创建切片,但它在python3中被删除了。
是否有一种方法可以在每次使用我的容器时,给出正确的类型提示,而不必强制类型提示?
发布于 2021-09-09 07:32:18
您希望使用typing.overload,它允许您使用类型检查器注册一个函数的多个不同签名。使用@overload修饰的函数在运行时被忽略,因此通常只需使用文字省略号...、pass或docstring来填充正文。这也意味着您必须保留至少一个没有使用@overload修饰的函数版本,这将是运行时使用的实际函数。
如果您查看typeshed (大多数主要类型检查器用于检查标准库的存根文件的存储库),您会发现这是它们在自定义容器(如collections.UserList )中注释__getitem__方法的技术。在您的例子中,您可以这样注释您的方法:
from typing import overload, Union, List
class CustomContainer:
def __init__(self, values: List[int]):
self.values = values
@overload
def __getitem__(self, item: int) -> int:
"""Signature when the function is passed an int"""
@overload
def __getitem__(self, item: slice) -> CustomContainer:
"""Signature when the function is passed a slice"""
def __getitem__(self, item: Union[int, slice]) -> Union[int, CustomContainer]:
"""Actual runtime implementation"""
if isinstance(item, slice):
return CustomContainer(self.values[item])
return self.values[item]
a = CustomContainer([1, 2])
b = a[0]
c = a[:]
reveal_type(b)
reveal_type(c)运行它通过MyPy,它将告诉我们:
main.py:24: note: Revealed type is "builtins.int"
main.py:25: note: Revealed type is "__main__.CustomContainer"再读
@overload的类型文档可以找到这里。
https://stackoverflow.com/questions/69113269
复制相似问题