One skill a day: Any and TypeVar, make the IDE’s auto-completion easier to use

Original link: https://www.kingname.info/2022/05/29/any-vs-typevar/

I believe that many students will use type annotations to improve the readability of the code when writing Python, and also help the IDE to achieve automatic completion.

Suppose we now get an object, this object may be a list or a generator, I write a function to get its first element. The code is simple:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
33
 from typing import Iterator
from contextlib import suppress


class People :
def __init__ (self, name) :
self.name = name

def eat (self) :
print( f' {self.name} is eating' )

def walk (self) :
print( f' {self.name} is walking' )


def get_first_element (ele_list) :
if isinstance(ele_list, list):
return ele_list[ 0 ] if ele_list else None
if isinstance(ele_list, Iterator):
with suppress(Exception):
value = next(ele_list)
return value
return None


if __name__ == '__main__' :
kingname = People( 'kingname' )
pm = People( 'pm' )
people_list = [kingname, pm]

obj = get_first_element(people_list)
if obj:
print(obj.)

The code is written, but when I get the first element and want to print the data in it, I find that I forgot what properties the People class has, and at this time, the auto-completion of PyCharm also fails, and I cannot It is very inefficient to not turn the code back to find the location defined by People. As shown below.

If we use type annotations, we can solve this problem:

Everyone knows this routine.

Now the question is, in addition to the People class, we also have the Cat class, and the elements in the list may all be instances of the People class, or they may all be instances of the Cat class. What should we do in this situation?

First of all, you have encountered the first problem, how to write the type annotation of the parameter of get_first_element ?

You might write something like this:

 1
 def get_first_element (ele_list: Union[List[Union[People, Cat]], Iterator[Union[People, Cat]]])

What if there is also a Dog class?

To simplify things, you might use Any , type, so get_first_element becomes like this:

 1
2
3
4
5
6
7
8
 def get_first_element (ele_list: Union[List[Any], Iterator[Any]]) -> Optional[Any]:
if isinstance(ele_list, list):
return ele_list[ 0 ] if ele_list else None
if isinstance(ele_list, Iterator):
with suppress(Exception):
value = next(ele_list)
return value
return None

Now you find that the problem comes again, PyCharm’s autocompletion is broken again. Because Any is any type, it doesn’t actually know what you’re returning until the code runs. As shown below:

In this case, you need to use泛型in Python type annotations. We know that generics are a concept in static languages, and Python also has types due to the use of type annotations. So the concept was borrowed.

Let’s see how to use it:

 1
2
3
 from typing import TypeVar

T = TypeVar( 'T' )

Note that the variable name T here and the parameter 'T' of TypeVar can be written as arbitrary strings at the same time, but the variable name must be consistent with the parameter. E.g:

 1
 GodType = TypeVar( 'GodType' )

Then just use T as Any . Let’s take a look at the effect:

As you can see, PyCharm can automatically complete again. Using TypeVar , you can tell PyCharm that the returned type is the same as the type corresponding to T in the incoming parameter. For example, in the incoming parameter, T is in List[T] or Generator[T] , so the returned parameter needs to be consistent with the elements in the list or the element type in the generator.

Let’s test it with the Cat generator and find that it can also be autocompleted:

What’s more, what if there are instances of Cat and instances of People in my list? At this time, PyCharm will directly list the possible completions of the two instances for you:

This article is reprinted from: https://www.kingname.info/2022/05/29/any-vs-typevar/
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment