c z
c z

Reputation: 9027

Why is mypy complaining about list comprehension when it can't be annotated?

Why does Mypy complain that it requires a type annotation for a list comprehension variable, when it is impossible to annotate such a variable using MyPy?

Specifically, how can I resolve the following error:

from enum import EnumMeta

def spam( y: EnumMeta ):
    return [[x.value] for x in y] 🠜 Mypy: Need type annotation for 'x' 

cast doesn't work:

return [[cast(Enum, x).value] for x in y] 🠜 Mypy: Need type annotation for 'x'  

Even though Mypy doesn't support annotations (x:Enum) in such a case I see the usage of the variable can be annotated using cast (see this post). However, cast(Enum, x) doesn't stop Mypy complaining that the variable isn't annotated in the first place.

#type: doesn't work:

return [[x.value] for x in y] # type: Enum 🠜 Mypy: Misplaced type annotation

I also see that a for loop variable can be annotated using a comment, # type: (see this post). However, # type: Enum doesn't work for list comprehension's for.

Upvotes: 16

Views: 8039

Answers (2)

MisterMiyagi
MisterMiyagi

Reputation: 52089

In a list comprehension, the iterable must be cast instead of the elements.

from typing import Iterable, cast
from enum import EnumMeta, Enum

def spam(y: EnumMeta):
    return [[x.value] for x in cast(Iterable[Enum], y)]

This allows mypy to infer the type of x as well. In addition, at runtime it performs only 1 cast instead of n casts.

If spam can digest any iterable that produces enums, it is easier to type hint this directly.

from typing import Iterable
from enum import Enum

def spam(y: Iterable[Enum]):
    return [[x.value] for x in y]

Upvotes: 25

Alex Waygood
Alex Waygood

Reputation: 7569

MisterMyagi's answer is the best solution for this specific case. It may be worth noting, however, that it is also possible to declare the type of a variable before that variable is defined. The following also passes MyPy:

from enum import Enum

def spam(y: type[Enum]):
    x: Enum
    return [[x.value] for x in y]

Upvotes: 6

Related Questions