Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I ensure that arguments have same type without listing the types explicitly?

Let us assume that we need a function that accepts two arguments of any type as long as both arguments have the same type. How would you check it statically with mypy?

If we only need the function to accept some finite amount of already known types, it is easy:

from typing import TypeVar, List, Callable

T = TypeVar('T', int, str, List[int], Callable[[], int])

def f(a: T, b: T) -> None:
   pass

f(1, 2)
f("1", "2")
f([1], [2])
f(lambda: 1, lambda: 2)
f(1, "2") # mypy will print an error message

For this code, mypy can ensure that the arguments to f are either two ints or two strs or two lists of ints or two functions of zero arguments that return int.

But what if we don't know the types in advance? What if we need something similar to let f (a:'t) (b:'t) = () from F# and OCaml? Simply writing T = TypeVar('T') would make things like f(1, "2") valid, and this is not what we want.

like image 501
zabolekar Avatar asked Oct 14 '16 00:10

zabolekar


People also ask

What are the two different ways to pass arguments into functions?

There are two ways to pass parameters in C: Pass by Value, Pass by Reference.

Can you specify argument type in Python?

5 Types of Arguments in Python Function Definition: keyword arguments. positional arguments. arbitrary positional arguments. arbitrary keyword arguments.

What are the 3 types of arguments in Python?

Hence, we conclude that Python Function Arguments and its three types of arguments to functions. These are- default, keyword, and arbitrary arguments.

Can you specify types in Python?

Specify a Variable Type There may be times when you want to specify a type on to a variable. This can be done with casting. Python is an object-orientated language, and as such it uses classes to define data types, including its primitive types.


1 Answers

What you're asking for is impossible (see below for explanation). But usually, there's no need in python to require that two arguments have precisely identical type.

In your example, int, str, List[int], Callable[[], int] don't have any common methods or attributes (other than what any two object instances have), so unless you manually check the type with isinstance, you can't really do anything with your argument that you couldn't do with object instances. Could you explain your use case?

Explanation of why you can't enforce type equality

Mypy type system has subtyping. So when you write f(a, b), mypy only checks that types of a and b are both subtypes of T rather than precisely equal to T.

In addition mypy subtyping system is mostly pre-defined and not under the programmer control, in particular every type is a subtype of object. (IIUC, in OCaml the programmer needs to say explicitly which types should be in a subtyping relationship, so by default every type constraint is equality constraint. That's why you could do what you wanted in OCaml).

So, when you write

T = TypeVar('T')
f(a: T, b: T) -> None: ...
f(x, y)

you are only telling mypy that the types of x and y must be subtypes of some common type T. And of course, this constraint is always (trivially) satisfied by inferring that T is object.

Update

To your question in the comment (is it possible to ensure that type of y is of subtype of type of x?), the answer is also no.

Even though mypy allows a type variable to be bounded from above by a specified type, that bound cannot be another type variable, so this won't work:

T = TypeVar('T')
U = TypeVar('U', bound=T, contravariant=True) # error, T not valid here
f(x: T, y: U) -> None
like image 179
max Avatar answered Sep 30 '22 14:09

max