Zoinks
Zoinks

Reputation: 361

Python Typing: how to get Type[C] to work with TypeVars and Generics?

I am trying to figure out how to get Python generic type-hinting to play nice with a constructor argument of Type[C]. Consider this code sample:

class Foo(object):
  fooval: str

  def __init__(self, val):
    self.fooval = val

class Bar(object):
  barval: str

  def __init__(self, val):
    self.barval = val

T = TypeVar('T', Foo, Bar)

class FooBarContainer(Generic[T]):
  child: T

  # Type[T] seems logical here, but that's not valid according to the docs
  def __init__(self, ctorable: Type[Union[Foo, Bar]], val):
    self.child = ctorable(val)

baz = FooBarContainer(Foo, val)
# This does not get flagged by type-checkers, but will obviously fail at runtime
failure = baz.child.barval

Attempting to use Type[T] results in a type-checker error:

Expected Type[T], got Type[Foo]

So the goal here is to figure out how to get TypeVars to work with the Type[C] from typing. This way static analysis would know that when I call a particular func with a particular Type[T], I am expecting to get T back. I can't seem to find any docs that would help me here.

The same issue arises when dealing with functions too. For example, this is valid syntax, but obviously not valid in terms of typing:

def initor(thing_type: Type[Union[Foo, Bar]], val) -> T:
  return thing_type(val)

Upvotes: 2

Views: 1756

Answers (1)

Michael0x2a
Michael0x2a

Reputation: 64308

Can you clarify what you mean by "Type[T] seems logical here, but that's not valid according to the docs"?

In particular, what docs are you looking at? The following code works as expected for me, using mypy 0.630:

class FooBarContainer(Generic[T]):
  child: T

  def __init__(self, ctorable: Type[T], val) -> None:
    self.child = ctorable(val)

val = 3
baz = FooBarContainer(Foo, val)

# Mypy reports a `"Foo" has no attribute "barval"` error
failure = baz.child.barval  

If the docs imply giving ctorable a type of Type[T] does not work, they should probably be updated.

Upvotes: 1

Related Questions