Skip to content

How do I type a generic factory function? #6073

Closed
@njsmith

Description

@njsmith

[Not sure if this is the right place to file issues like this, feel free to tell me to go somewhere else :-)]

I have two generic types:

class SendChannel(Generic[T]):
    ...

class ReceiveChannel(Generic[T]):
    ...

I have a factory function that creates a linked pair of these objects:

def open_channel_pair(buffer_size: int) -> Tuple[SendChannel[T], ReceiveChannel[T]]:
    # ... construct some objects ...
    return (s, r)

I would like to allow people to call it like:

s, r = open_channel_pair[str](0)
# Now 's' is a SendChannel[str], and 'r' is a ReceiveChannel[str]

This works for the factory callables built into the language, e.g. calling SendChannel[str]() returns an object of type SendChannel[str]. This is basically the same thing, but since I have to construct two objects in a single operation, the regular thing doesn't work.

I did come up with a sneaky hack:

# Complete cut-and-pasteable example
from typing import Generic, TypeVar, Tuple

T = TypeVar("T")

class SendChannel(Generic[T]):
    pass

class ReceiveChannel(Generic[T]):
    pass

class open_channel_pair(Tuple[SendChannel[T], ReceiveChannel[T]]):
    def __new__(self, buffer_size: int):
        return (SendChannel[T](), ReceiveChannel[T]())

    # Note: this function is unreachable, but we have to define it, and keep
    # its signature in sync with __new__'s signature, to make mypy happy.
    def __init__(self, buffer_size: int) -> None:
        assert False

s, r = open_channel_pair[str](0)
# Confirms that it works:
reveal_type(s)
reveal_type(r)

This is gross, though. Is there any way to define a regular callable that has the same type as a generic class constructor, but is less gross than this?

What even is the type of a generic class constructor? reveal_type(SendChannel) prints def [T] () -> SendChannel[T`1], which is a very strange looking type.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions