简体   繁体   中英

How do I correcly specify fixed-length sequences in mypy?

When I write a function expecting a specific-length tuple, I can type the argument with Tuple[int, int] (for a specific length of two).

from typing import Tuple


def tuple_in(a_tuple: Tuple[int, int]) -> Tuple[int, int]:
    return a_tuple


tuple_in((0, 1))  # mypy is happy

That's great as long as I have a tuple to pass. If I don't have a tuple, I have trouble casting whatever I do have into a tuple.

tuple_in(tuple([0, 1]))  # Expected Tuple[int, int], got Tuple[int, ...]

tuple_in(tuple(x for x in [0, 1]))  # Expected Tuple[int, int], got Tuple[int, ...]

tuple_in(tuple(x for x in [0, 1][:2]))  # Expected Tuple[int, int], got Tuple[int, ...]

I get it. Casting an argument of indeterminate length yields a tuple of indeterminate length. But that makes my life difficult.

This works, but it's not really work able with more than 2-3 values

my_list = [0, 1]
tuple_in((my_list[0], my_list[1]))  # mypy is happy. My eyes hurt.

The typing module has a cast function to cast those Tuple[int, ...] into Tuple[int, int] , but that's no better than type: ignore .

tuple_in(cast(Tuple[int, int], "obviously not a tuple"))  # mypy is happy

Fortunately, the typing module offers a better solution: NamedTuple

from typing import NamedTuple

TwoInts = NamedTuple("TwoInts", [("a", int), ("b", int)])


def named_tuple_in(a_tuple: TwoInts) -> Tuple[int, int]:
    return a_tuple


named_tuple_in(Tuple2(*[0, 1]))  # mypy is happy

BUT, if I want to call tuple_in from outside the module, I've got to import TwoInts . That seems like overkill, and it means my editor won't give me much of a hint (only the name of my NamedTuple).

I like the NamedTuple solution when my argument makes sense as a weak class (eg, Vector3, GenusSpecies, Address), but it doesn't feel like the best solution for generic, fixed-length arguments (eg, TwoInts, FourteenScalars, ThreeNames).

What is the intended way to type such fixed-length arguments?

I found it!!

from typing import Tuple


def tuple_in(a_tuple: Tuple[int, int]) -> Tuple[int, int]:
    return a_tuple


tuple_in([0, 1])[:2]  # mypy is happy!!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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