Tuple Typing with at least x number of types
Asked Answered
D

2

7

Based on the documentation for Python Typing, these are the ones that deal with Tuples...

  • Tuple[()] - empty tuple
  • Tuple[int, int] - tuple of two int objects
  • Tuple[int, ...] - tuple of an arbitrary number of int objects

I want to create a type where I have a Tuple with at least 8 ints. My goal is somewhere in between the last two types (Tuple[int, int], and Tuple[int, ...]).

If the tuple has...

  • 8 ints? Good
  • 9 ints? Good
  • 32 ints? Good
  • 4 ints? Bad
  • 1 int? Bad

Is this even possible where PyCharm will not throw warnings? Here is what I tried below. However, PyCharm will "incorrectly" give me warnings on the assert statement

# Type Alias 
Byte = Tuple[int, int, int, int, int, int, int, int]           # 8 bits
Nibble = Tuple[int, int, int, int]                             # 4 bits

# BytePlus Type is not correct. The following code does not work
BytePlus = Tuple[int, int, int, int, int, int, int, int, ...]  # 8+ bits


def adder(byte1: Union[Byte, BytePlus], byte2: Byte) -> Byte:
    pass

# Incorrect warnings for parameters. 
# What I see...
#    - parameter 1 (Byte | BytePlus) has no warning, but it should. nibble = 4 bits
#    - parameter 2 (Byte) has a warning, good, but it will have a warning for 9 bits
assert adder(nibble(4), nibble(10)) == byte(14)

Here is the code for nibble() and byte() if you want...

def byte(number) -> Byte:
    return (
        (number & 128) // 128,
        (number & 64) // 64,
        (number & 32) // 32,
        (number & 16) // 16,
        (number & 8) // 8,
        (number & 4) // 4,
        (number & 2) // 2,
        (number & 1) // 1
    )


def nibble(number) -> Nibble:
    return (
        (number & 8) // 8,
        (number & 4) // 4,
        (number & 2) // 2,
        (number & 1) // 1
    )
Disseisin answered 21/1, 2018 at 18:36 Comment(1)
@PatrickArtner I am looking over BitArray. I would prefer an immutable type,though, so the question still standsDisseisin
C
2

PEP 646, which introduced variadic generics, also allows tuple types to be unpacked:

TripleInt: TypeAlias = tuple[int, *tuple[int, int]]
# TripleInt = tuple[int, int, int]

As tuple[int, ...] denotes a tuple with 0 or more int elements, the type of a tuple consisting of at least 8 int elements would be:

(playgrounds: Mypy, Pyright (PEP 695 syntax))

Byte: TypeAlias = tuple[
    int, int, int, int, int, int, int, int,  # 8 `int`
    *tuple[int, ...]
]

For 3.10 and older, the unpacking operator would cause a SyntaxError and thus will need to be replaced with Unpack:

Byte: TypeAlias = tuple[
    int, int, int, int, int, int, int, int,  # 8 `int`
    Unpack[tuple[int, ...]]
]
Cornetist answered 23/4 at 3:0 Comment(0)
A
0

Building on InSync's answer: with the new type statement of Python 3.12 we can easily create a generic type alias:

type AtLeastEight[T] = tuple[T, T, T, T, T, T, T, T, *tuple[T, ...]]
type Byte = AtLeastEight[int]

This can be used to also create a generic type alias for tuples with at least one element, something which I needed for my own project:

type OneOrMore[T] = tuple[T, *tuple[T, ...]]

def foo(bytes: OneOrMore[Byte]):
   ...

Unfortunately, I couldn't parametrize the number of types for something like AtLeastN[T, N], although this could be possible with Annotated at one point.

Alchemist answered 9/8 at 20:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.