How to typehint a generic function?

Viewed 1990

Say I want to define something in Python works exactly the same as the following function in Java:

public <T> void func(T a, T b):
     ...

This code simply means that func can take any a and b as input as long as they have the same data type.

Python doesn't have an explicit type check itself, but now I am using mypy to check my code. My attempts are as follows:

T = TypeVar('T')

def func(a: Generic[T], b: Generic[T]):
         ...
func(1, 3)  # this should be a legal input since 1 and 3 are both int

and

T = TypeVar('T')

class A(Generic[T]):
    pass

def func(a: A[T], b: A[T]):
    ...
func(1, 3)

However, mypy reports errors for both of them. Is there a way for us to define such generic function just as in Java to pass mypy check? I know for the purpose of sanity check for my code, I can also check whether type(a) equals type(b) inside the function, but this is not my purpose. I am specifically interested in my question as it is, i.e., how to define such a generic function to pass mypy check?

1 Answers

That Java function doesn't actually do what you want it to, and a Python equivalent wouldn't do what you want it to either.

You want to make sure that the Java function is always called with two arguments of the same type, but any two objects you could possibly pass it share a type. Specifically, any two objects are instances of Object. (null and primitives complicate things a little, but they won't stop calls from type-checking.) Any call will type check, and your attempt to use generics won't do a thing.

Similarly, the Python equivalent would be

def func(a: T, b: T):
    ...

and like the Java code, any call will type check, because any two objects are instances of object.


There's no way to specify a constraint of type(a) is type(b) with type annotations. It's usually the wrong constraint, anyway. What you usually want to specify is that the arguments are compatible with each other in some way. Unfortunately, there isn't really a good way to do that either.

For example, if you wanted to specify that two arguments are comparable with each other in Java, that would be

public <T extends Comparable<T>> void func(T a, T b) {...}

However, Python type variables don't support parameterized bounds like that.

Related