Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
452 views
in Technique[技术] by (71.8m points)

python - 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...