mypy: creating a type that accepts list of instances of subclasses

房东的猫 提交于 2019-12-06 13:19:12

Passing in a list here is fundamentally not type-safe. For example, what if you do this?

def func(objects: List[Parent]) -> None:
    print(objects)
    objects.append(Parent())

children: List[Child] = [Child(), Child(), Child()]
func(children)
# Uh-oh! 'children' contains a Parent()!

If this were permitted to type check, your code would end up containing a bug.

To use type-jargon, List is intentionally designed to be an invariant type. That is, even though Child is a subclass of Parent, it is not the case that List[Child] is a subtype of List[Parent], or vice-versa. You can find more info about invariance here and here.

The most common alternative is to use Sequence instead, which is a read-only interface/protocol/whatever. And since Sequence is read-only, it's safe for it to be covariant: that is, Sequence[Child] is considered to be a valid subtype of Sequence[Parent].

Depending on what exactly you're doing, you may be able to use type variables instead. E.g. instead of saying "this function takes in a list of Parent", you say "this function takes in a list of any class which is Parent, or a subclass of Parent":

TParent = TypeVar('TParent', bound=Parent)

def func(objects: List[TParent]) -> List[TParent]:
    print(objects)

    # Would not typecheck: we can't assume 'objects' will be a List[Parent]
    objects.append(Parent())  

    return objects

Depending on what exactly you're doing, you could maaaaaaaaybe create a custom Protocol that defines a write-only list-like collection (or a custom data structure). And since your data structure would be write-only, you could make it contravariant -- that is, WriteOnlyThing[Parent] would be a subtype of WriteOnlyThing[Child]. You then make func accept WriteOnlyThing[Child] and could safely pass in instances of both WriteOnlyThing[Child] and WriteOnlyThing[Parent].

If neither approach works in your case, your only recourse is to either use # type: ignore to silence the error (not recommended), give up on type-checking the contents of the list and make the argument of type List[Any] (also not recommended), or figure out how to restructure your code so it's type-safe.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!