在Python中使用适当的类型提示对类序列进行子类化

时间:2017-10-11 13:52:28

标签: python typechecking mypy

我正在尝试在Python中实现一种自定义序列类:

//  TextFieldScrollView
#import <UIKit/UIKit.h>

@interface TextFieldScrollView : UIScrollView

@property (assign, nonatomic) IBInspectable BOOL preventAutoScroll;

@end

@implementation TextFieldScrollView

- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated {
    if (self.preventAutoScroll == NO) {
        [super scrollRectToVisible:rect animated:animated];
    }
}

@end

现在我想检查 mypy 是否知道from typing import Sequence, TypeVar, List T = TypeVar('T') class MySequence(Sequence[T]): def __init__(self): self._container: Sequence[T] = [] def __getitem__(self, idx): return self._container[idx] def __len__(self): return len(self._container) 的元素是MySequence类型的项目:

T

所以它失败了: mypy foo: MySequence[str] = MySequence() reveal_type(foo[0]) # Revealed type is 'Any' 的项目一无所知。普通foo的相同示例有效:

Sequence

如果我正在尝试向bar: Sequence[str] = [] reveal_type(bar[0]) # Revealed type is 'builtins.str*' 实施添加类型注释,我还有另一个错误:

__getitem__

我也试过

def __getitem__(self, idx) -> T:
# Signature of "__getitem__" incompatible with supertype "Sequence"

因为def __getitem__(self, idx) -> Union[T, Sequence[T]]: 可以是一个切片,在这种情况下,我的代码将返回一个序列而不是一个元素。它使用相同的消息失败。

正如my previous question中所讨论的那样,问题就是open discussion

但是,我仍然想知道,是否可以创建自定义序列类型,允许 mypy 提取有关其项目类型的信息,例如在我的示例中?

1 个答案:

答案 0 :(得分:5)

在这种情况下,正确的做法是正确覆盖exact signature for __getitem__,包括重载。

from typing import Sequence, TypeVar, List, overload, Union

T = TypeVar('T', covariant=True)

class MySequence(Sequence[T]):
    def __init__(self):
        self._container: Sequence[T] = []

    @overload
    def __getitem__(self, idx: int) -> T: ...

    @overload
    def __getitem__(self, s: slice) -> Sequence[T]: ...

    def __getitem__(self, item):
        if isinstance(item, slice):
            raise Exception("Subclass disallows slicing")

        return self._container[item]

    def __len__(self) -> int:
        return len(self._container)

foo: MySequence[str] = MySequence()
reveal_type(foo[0])

(请注意,我创建了typevar协变。严格来说,这不是必需的,但如果容器实际上意味着代表“只读”类型的结构,我们也可以获得最大的灵活性。 )

注意:mypy在第一个示例中确定返回类型为Any的事实是预期的行为。根据PEP 484,任何没有类型注释的方法或签名都被视为参数和返回类型都是Any

这是一种设计机制,默认情况下无类型Python代码被视为完全动态。

Mypy内置了各种命令行参数,您可以尝试强制它来检查无类型函数的内容(我相信它是--check-untyped-defs?),尽管它不会尝试推断返回类型是什么。