[Python] Type hint for a dict that maps tuples containing classes to the corresponding...

Discussão em 'Python' iniciado por Stack, Julho 11, 2025.

  1. Stack

    Stack Membro Participativo

    I'm making a semi-singleton class Foo that can have (also semi-singleton) subclasses. The constructor takes one argument, let's call it a slug, and each (sub)class is supposed to have at most one instance for each value of slug.

    Let's say I have a subclass of Foo called Bar. Here is an example of calls:

    1. Foo("a slug") -> returns a new instance of Foo, saved with key (Foo, "a slug").
    2. Foo("some new slug") -> returns a new instance Foo, saved with key (Foo, "some new slug").
    3. Foo("a slug") -> we have the same class and slug from step 1, so this returns the same instance that was returned in step 1.
    4. Bar("a slug") -> we have the same slug as before, but a different class, so this returns a new instance of Bar, saved with key (Bar, "a slug").
    5. Bar("a slug") -> this returns the same instance of Bar that we got in step 4.

    I know how to implement this: class dictionary associating a tuple of type and str to instance, override __new__, etc. Simple stuff.

    My question is how to type annotate this dictionary?

    What I tried to do was something like this:

    FooSubtype = TypeVar("FooSubtype", bound="Foo")

    class Foo:
    _instances: Final[dict[tuple[Type[FooSubtype], str], FooSubtype]] = dict()


    So, the idea is "whatever type is in the first element of the key ("assigning" it to FooSubtype type variable), the value needs to be an instance of that same type".

    This fails with Type variable "FooSubtype" is unbound, and I kinda see why.

    I get the same error if I split it like this:

    FooSubtype = TypeVar("FooSubtype", bound="Foo")
    InstancesKeyType: TypeAlias = tuple[Type[FooSubtype], str]

    class Foo:
    _instances: Final[dict[InstancesKeyType, FooSubtype]] = dict()


    The error points to the last line in this example, meaning it's the value type, not the key one, that is the problem.

    mypy also suggests using Generic, but I don't see how to do it in this particular example, because the value's type should somehow relate to the key's type, not be a separate generic type.

    This works:

    class Foo:
    _instances: Final[dict[tuple[Type["Foo"], str], "Foo"]] = dict()


    but it allows _instance[(Bar1, "x")] to be of type Bar2 (Bar1 and Bar2 here being different subclasses of Foo). It's not a big problem and I'm ok with leaving it like this, but I'm wondering if there is a better (stricter) approach.

    Continue reading...

Compartilhe esta Página