简体   繁体   English

列表子类的 Python 类型

[英]Python typing for a subclass of list

I want to be able to define what the contents of a subclass of list have to be.我希望能够定义列表子类的内容。 The class would look like the following.该类将如下所示。

class A(list):
   def __init__(self):
      list.__init__(self)

I want to include typing such that the following would happen.我想包括打字,以便发生以下情况。

import typing

class A(list: typing.List[str]):  # Maybe something like this
   def __init__(self):
      list.__init__(self)

>> a = A()
>> a.append("a")  # No typing error
>> a.append(1)  # Typing error

typing conveniently provides a generic version of collections.MutableSequence , so something to the effect of: typing方便地提供了collections.MutableSequence的通用版本,因此具有以下效果:

import typing

T = typing.TypeVar('T')
class HomogeneousList(typing.MutableSequence[T]):
    def __init__(self, iterable: typing.Iterable[T]=()) -> None:
        self._data: typing.List[T]  = []
        self._data.extend(iterable)

    @typing.overload
    def __getitem__(self, index: int) -> T: ...
    @typing.overload
    def __getitem__(self, index: slice) -> HomogeneousList[T]: ...
    def __getitem__(self, index):
        return self._data[index]

    @typing.overload
    def __setitem__(self, index: int,  item: T) -> None: ...
    @typing.overload
    def __setitem__(self, index: slice, item: typing.Iterable[T]) -> None: ...
    def __setitem__(self, index, item):
        self._data[index] = item

    def __delitem__(self, index: typing.Union[int, slice]) -> None:
        del self._data[index]

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

    def insert(self, index: int, item: T) -> None:
        self._data.insert(index, item)


string_list = HomogeneousList[str]()
string_list.append('foo')
string_list.append(42)


int_list = HomogeneousList[int]()
int_list.append(42)
int_list.append('foo')

Now, mypy gives the following errors:现在, mypy给出以下错误:

test.py:36: error: Argument 1 to "append" of "MutableSequence" has incompatible type "int"; expected "str"
test.py:41: error: Argument 1 to "append" of "MutableSequence" has incompatible type "str"; expected "int"

There is some tricky aspects of typing __getitem__ etc because they accept slice objects as well, but not terrible.输入__getitem__等有一些棘手的方面,因为它们也接受slice对象,但并不可怕。

Note, this is useful, because if you just try to do:请注意,这很有用,因为如果您只是尝试执行以下操作:

class HomogeneousList(collections.abc.MutableSequence, typing.Generic[T]):
    ....

MyPy, at least, doesn't throw an error for append.至少,MyPy 不会为追加引发错误。 AFAIKT you'd have to explicitly add:' AFAIKT 你必须明确添加:'

def append(self, item: T) -> None:
    self._data.append(item)

Which sort of removes a lot of the utility of collections.abc.MutableSequence to begin with.哪种类型的开头删除了collections.abc.MutableSequence的许多实用程序。 Anyway, thankfully, typing provides generic versions of all of these out of the box!无论如何,幸运的是,打字提供了所有这些开箱即用的通用版本!

Note, you can use these generically, like I've show, but you can also do something like:请注意,您可以像我展示的那样一般地使用这些,但您也可以执行以下操作:

class StringList(HomogeneousList[str]):
    pass

mylist = StringList([1,2,3]) # mypy error
mylist = StringList('abc') # no error

mylist.append('foo') # no error
mylist.append(42) # mypy error

Prior to Python 3.9, you can use:在 Python 3.9 之前,您可以使用:

import typing

class A(typing.List[str]):
    pass

This indicates to your type checker that elements of class A should be of type str .这向您的类型检查器表明AA元素应该是str类型。 At run-time, this behaves the same as creating a subclass of list .在运行时,这与创建list的子类的行为相同。 PEP 484 specifies how the typing system behaves. PEP 484指定了打字系统的行为方式。 In particular, the example in this section of the PEP does something similar to what you're asking, but with typing.Dict instead of typing.List .特别是, PEP 的这一部分中的示例执行的操作与您所要求的类似,但使用typing.Dict而不是typing.List

In Python 3.9+, you can use the built-in type instead of importing from typing .在 Python 3.9+ 中,您可以使用内置类型而不是从输入中导入 The class becomes:类变为:

class A(list[str]):
    pass

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

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