Home > Software engineering >  How can I properly type annotate an expression that builds a List of Sequences?
How can I properly type annotate an expression that builds a List of Sequences?

Time:06-24

I want to build a list that contains tuples or lists of strings. I want:

x = [('foo',)]   [('bar', 'baz')]

(Obviously I could create a single list initially instead of splicing two lists together in this simplified example. Pretend that one of them is the result of a function call or list comprehension.)

mypy complains:

List item 0 has incompatible type "Tuple[str, str]"; expected "Tuple[str]"

Okay, it infers that I'm adding a Tuple[str] to a Tuple[str, str] and doesn't like that I'm creating a heterogeneous list. However, the list is homogeneous from a different perspective; I want it to be a typing.List[typing.Sequence[str]].

Is there a nice way to convince mypy of this? I tried annotating x:

x: typing.List[typing.Sequence[str]] = [('foo',)]   [('bar', 'baz')]

but mypy still complains. It additionally complains:

Incompatible types in assignment (expression has type "List[Tuple[str]]", variable has type "List[Sequence[str]]")
"List" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance
Consider using "Sequence" instead, which is covariant

Breaking up the expression works:

x: typing.List[typing.Sequence[str]] = []
x.append(('foo',))
x.append(('bar', 'baz'))

or adding explicit casts:

x = ([typing.cast(typing.Sequence[str], ('foo',))]
       [typing.cast(typing.Sequence[str], ('bar', 'baz'))])

but both workarounds are much uglier than I'd like.

CodePudding user response:

I realized that I only need to add an explicit cast for the first expression:

x = ([typing.cast(typing.Sequence[str], ('foo',))]
       [('bar', 'baz')])

which isn't quite as nice as being able to annotate x, but at least it's in only one place.

CodePudding user response:

Can you give a static type to your 2 lists? I have tried this and the syntax checker does not complain

from typing import List, Sequence

list_one : List[Sequence[str]] = [('foo',)]
list_two : List[Sequence[str]] = [('bar', 'baz')]

x: List[Sequence[str]] = list_one   list_two
  • Related