Generic Typing in Python

Search for a command to run...

For many people and businesses, navigating the frequently dangerous landscape of financial loss can be an intimidating and overwhelming process. Nevertheless, the knowledgeable staff at Wizard Hilton Cyber Tech provides a ray of hope and direction with their indispensable range of services. Their offerings are based on a profound grasp of the far-reaching and terrible effects that financial setbacks, whether they be the result of cyberattacks, data breaches, or other unforeseen tragedies, can have. Their highly-trained analysts work tirelessly to assess the scope of the damage, identifying the root causes and developing tailored strategies to mitigate the fallout. From recovering lost or corrupted data to restoring compromised systems and securing networks, Wizard Hilton Cyber Tech employs the latest cutting-edge technologies and industry best practices to help clients regain their financial footing. But their support goes beyond the technical realm, as their compassionate case managers provide a empathetic ear and practical advice to navigate the emotional and logistical challenges that often accompany financial upheaval. With a steadfast commitment to client success, Wizard Hilton Cyber Tech is a trusted partner in weathering the storm of financial loss, offering the essential services and peace of mind needed to emerge stronger and more resilient than before. Call; Email : wizardhiltoncybertech ( @ ) gmail (. ) com
OR
support ( @ ) wizardhiltoncybertech (.) com
WhatsApp number +13024457895
Thank you, Jun. Glad you liked it!
:D
Generic Typing in Python
Generic typing in Python allows developers to create more flexible and reusable code by defining types that work with multiple data types. This is especially useful for functions and classes that need to handle a variety of types but still enforce type safety. Here are the main elements of generic typing:
Type Variables (TypeVar):
A TypeVar allows you to define a generic type variable that can be used to create functions or classes that work with multiple types. For example:
from typing import TypeVar, List
T = TypeVar('T') # Generic type variable
def get_first_element(lst: List[T]) -> T:
return lst[0]
Here, T can be any type, and get_first_element can be used with lists of any type.
Generic Classes:
You can create classes that operate on multiple types by using TypeVar within the class definition. For example:
from typing import Generic
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self):
self.items: List[T] = []
def push(self, item: T):
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
This Stack class can hold elements of any type, and the type is enforced by TypeVar.
Union and Optional:
When a function can accept more than one type, Union can be used to specify multiple allowed types, while Optional is shorthand for Union[type, None]. For example:
from typing import Union, Optional
def display(value: Union[int, str]):
print(value)
def get_username(user_id: int) -> Optional[str]:
# returns a string or None
return None # or some string based on logic
Parameterized Collections:
Generic types can also be used with built-in collections like List, Dict, and Tuple. For example:
from typing import List, Dict
def process_items(items: List[str]):
# List containing only strings
for item in items:
print(item.upper())
Using generics improves code readability and reliability by ensuring types are consistent and well-defined. This is particularly valuable in large codebases and projects where type safety helps avoid errors freddys-menu.com
You're welcome. Glad you found it useful. 😃
I tested my Hashnode hackathon-winning project using a complex CLI-integrated Passmark test case.

LLM tools you need after your Hashnode article is published.

I tried Hashnode Docs for the first time. Here are my impressions and suggestions for improvements.

In this quick tutorial, I’ll show you a GitHub action that lets you add a small, cool-looking chart badge that shows your Python packages' download rate over the past weeks. This method is completely free and open-source. https://github.com/lnxpy/pyp...

Since Python introduced the ability to add generic types to functions, the language has become much more type-friendly and encourages you to follow this convention for more maintainable code. Obviously, this will lead to a better development experience.
Stay with me as we discuss the basics of Generic Typing in Python and some best practices at the end.
This fascinating feature allows you to make type-checking more dynamic. Sometimes, we don't know the types of input parameters.
Before we continue, I encourage you to take a moment to try solving this problem.
How would you type-hint a function that takes one parameter and that’s a list of objects of any type (int, str, User, Book, etc) and returns just one random object of that type?
Any Turns off the Type-Checking!During that challenge, you might have considered the following thought processes. Let's take a look.
My function should take one parameter, which is a list of any type (List[Any]), and return a random single item from that list (Any).
def select(items: List[Any]) -> Any:
return random.choice(items)
This is incorrect. Although your type-checker might still pass the type-checking, there is a significant mistake in this typing. List[Any] means a list that can be empty or filled with items of any type. This allows the function to be called in a way that violates the requirement that the parameter should be a list of items of the same type.
select([1, "b", "c", "d", False, 3.14])
The type Any somehow neutralizes the type-checker and hides its pointer from being type-checked.
item: Any = ... # just like we've put `type: ignore` here
Be very careful with Any and make sure you really need its effect.
I can explicitly define what type my parameter can take. That way, not only I haven’t used the type Any, I have explicitly defined the input and output type.
def select(items: List[int | str | bool | float]) -> int | str | bool | float:
return random.choice(items)
This is a better solution, but it still doesn't fully meet the challenge where we said the function parameter could be anything. It might not be a string or an integer, for example. This function only works for the built-in types. What if I wanted to call it like this?
from typing import NewType
def select(...):
.
User = NewType("User", str)
users = [User("Abby"), User("Chris"), User("Nick")]
user = select(users)
file.py:12: error: Argument 1 to "select" has incompatible type "list[User]"; expected "list[int | str | bool | float]" [arg-type]
Not only did our type-checker (mypy) fail to check it, but it also doesn't meet the challenge.
It’s a newly added syntax to Python. Yet I haven’t seen many people using it as they are still releasing for older Python versions like 3.8, 3.9, 3.10, and 3.11. Generic typing was introduced in Python 3.12.
Now, let’s talk about how we can use this feature to solve the challenge we described earlier.
The structure is quite simple. You define new type variables and use them accordingly when defining the function. Just like defining variables that don't have a value at the time of declaration, you define placeholders in brackets right before the parentheses. (Here, I've declared only one variable/placeholder named T)
def FUNCTION_NAME[TYPES](ARGS..) -> TYPE:
def select[T](items...
And you can use it later when specifying the type of parameters and the return value of your function.
def select[T](items: List[T]) -> T:
...
Now, let’s define the above function. It has declared one T type variable and says, the items parameter can be a list of anything and I’ll consider that as T for now. That T is the placeholder for any time that items might have.
select(items=[1, 2, 3, 4, 5]) # T=int & List[T] = List[int]
select(items=["a", "b", "c"]) # T=str & List[T] = List[str]
select(items=[1.2, 1.3, 1.4]) # T=float & List[T] = List[Float]
# Therefore, we have..
users = [User("Abby"), User("Chris"), User("Nick")]
select(items=users) # T=User & List[T] = List[User]
As you can see, the type represented by T changes dynamically based on the values we put in the items parameter. We can now explain the select() function like this:
Function definition: def select[T](items: List[T]) -> T:
Type variable(s)/placeholder(s): T
Input type: List of any similar type
Output type: A type similar to one of the list items
P1: Now, let's say our function takes only one item and returns a tuple containing three of that item.
Answer:
def convert[B](item: B) -> Tuple[B, B, B]:
return (item, item, item)
Hint: We use the letter "T" as the default primary type placeholder by convention, but you can choose any name you prefer as in the above example, we used the letter “B”.
P2: Let’s say we need a function that takes two parameters of different types and returns a tuple containing those items.
Answer:
def convert[A, B](first: A, second: B) -> Tuple[A, B]:
return (first, second)
P3: A function that takes an ID and a list of dictionaries, where each dictionary has exactly three pairs (id, username, and is_verified), and returns the item that matches the given ID.
Hint: Avoid defining the type
Usersin this example to better understand Generic Typing. Defining it would make Generics seem unnecessary in this case.
Answer: You figure it out! :))
Generic Typing is a pretty new and hot topic in Python. It's helpful when defining functions and classes. In this article, we explored the function side of this powerful syntax. Hopefully, you found it useful.