Most Exciting Python Features from 3.7 to 3.11
Tags: python, programming, beginners
Published: 2023-03-10 06:49:19

## Introduction

Hey innovators, I am Yash Makan and in today’s blog post we are going to discuss about some of the cool and helpful features that you won’t wanna miss, to add in your coding cookbooks. I’ll be mentioning 10 interesting features based on each latest python version that will make you a python guru. So without any more introduction, let’s dive in.

![https://i.giphy.com/media/OuePMznpbHyrw34608/giphy.webp](https://i.giphy.com/media/OuePMznpbHyrw34608/giphy.webp)

## 1. Adding Notes When Catching Exception

This feature of adding notes to python exceptions is added in the version 3.11. Now, developers can add more detailed information while handling exceptions to make it much more easier in the debugging stage. It can be utilized by adding `add_note` method to the `Exception` class.

```python
try:
	raise TypeError
except Exception as e:
	e.add_notes("More Information regarding error")
	e.add_notes("Why not add some more info?")

----------------------------------------------------
Trackback (most recent call last):
	File "/main.py", 4, in <module>
		raise TypeError
TypeError
More Information regarding error
Why not add some more info?
```

## 2. Grouping Asynchronous  Tasks

Do you know, from python 3.11, we can group asynchronous tasks together using the `TaskGroup` class. This class helps in running multiple coroutines and wait for all those coroutines to finish. This can be used in multiple scenarios where multiple coroutines are used. Let’s see an example to better understand.

```python
import asyncio

async def coroutine_1():
    await asyncio.sleep(1)
    print("Coroutine 1")

async def coroutine_2():
    await asyncio.sleep(2)
    print("Coroutine 2")

async def main():
    async with asyncio.TaskGroup() as task_group:
        await task_group.create_task(coroutine_1())
        await task_group.create_task(coroutine_2())
		print("Both tasks are done now.")

asyncio.run(main())

----------------------------------------------------
Coroutine 1
Coroutine 2
Both tasks are done now.
```

## 3. square² and ∛cube root

Now python 3.11 has introduced a brand new update where developers can square or cube root any number.

…

I know what you guys are thinking but jokes aside, now we have inbuilt functions in the math module which helps us to do the exact same thing.

```python
>>> import math
>>> math.exp2(4)
16.0
>>> math.cbrt(8)
2.0
```

## 4. Pattern Matching

Have you ever heard of switch case in other languages and always felt that python is missing out on this feature. If so, then worry no more. Python 3.10+, now developers can use match-case which is similar to switch case but is much more better. In the case, you can compare not only literals but also tuples, variables etc. Let’s see an example to better understand.

```python
# point is an (x, y) tuple
match point:
	case (0, 0):
		print("Origin")
	case (0, y):
		print(f"x=0,y={y}")
	case (x, 0):
		print(f"x={x},y=0")
	case (x, y):
		print(f"x={x},y={y}")
	case _:
		raise ValueError("Not a point")
```

## 5. Union Alternative

You must have used `Union` from typing to tell compiler that the argument can either be int or float. Now from python 3.10, there’s a better way to do this. Instead of importing the `Union` class like `from typing import Union` You can use the same functionality with the `|` symbol.

```python
from typing import Union
def square(number: Union[int, float]) -> Union[int, float]:
	return number ** 2

vs

def square(number: int | float) -> int | float:
	return number ** 2
```

## 6. Dictionary Merge Operator

From python 3.9, merging two dictionaries together is much easier because of the dict merge operator. Earlier, if we want to merge two dictionaries we can do that by `dict3 = {**dict1, **dict2}` but now we can use the `|` symbol to merge two dictionaries.

```python
>>> dict1 = {"a": 1, "b": 2}
>>> dict2 = {"b": 3, "c": 4}
>>> {**dict1, **dict2}
{"a": 1, "b": 3, "c": 4}
>>> dict1 | dict2 # New way
{"a": 1, "b": 3, "c": 4}
```

## 7. Walrus Operator

The walrus operator allows developers, to assign and return value both at the same time. This feature was introduced in python 3.8. Let’s see an example to understand the `:=` operator,

```python
# Before Python 3.8
>>> numbers = [2, 8, 0, 1, 1, 9, 7, 7]
>>> num_length = len(numbers)
>>> num_sum = sum(numbers)
>>> description = {
...     "length": num_length,
...     "sum": num_sum,
...     "mean": num_sum / num_length,
... }
>>> description
{'length': 8, 'sum': 35, 'mean': 4.375}

# With Walrus Operator
>>> numbers = [2, 8, 0, 1, 1, 9, 7, 7]
>>> description = {
...     "length": (num_length := len(numbers)), # Here we are initializing and using both at the same time
...     "sum": (num_sum := sum(numbers)),
...     "mean": num_sum / num_length,
... }
>>> description
{'length': 8, 'sum': 35, 'mean': 4.375}
```

## 8. **f-strings support `=` for self-documenting**

In python 3.8, other interesting feature added is the f-string support for self documenting and debugging. Many of the times developers use `print(f"check {variable}")` to debug if the variable value is updated or not. Now, python 3.8 introduced a much better way to debug this exact same thing.

```python
variable = get_data()
print(f"{variable=}") # variable='Hello World!'
```

## 9. Positional-only Parameters

In Python 3.8, positional-only parameter feature is added. Now, in a `def` function we can define which of our parameters can be positional only and keyword only parameters. This is done by separating the parameters by a `/` Let’s see an example,

```python
def foo(a, b, /, **kwargs):
    print(a, b, kwargs)

>>> foo(10, 20, c=30, d=40, e=50) # correct as a and b must be a positional argument
10, 20, {'c': 30, 'd': 40,'e': 50}
```

## 10. Dataclasses

In Python 3.7, dataclasses are introduced. This feature will save you from writing ton of boilerplate code and makes your classes neat. This feature is one of may favorite as well. We can simply add the dataclass decorator to our class and it can generate most of the magic methods on it’s own such as `__repr__()` `__eq__()` and `__hash__()` Let’s see an example,

```python
from dataclasses import dataclass
@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0

p = Point(1.5, 2.5)
print(p)   # Point(x=1.5, y=2.5, z=0.0)
```

## Conclusion

So in today’s article we have covered python’s most exciting features from Python 3.7 to 3.11 . Now Of course, there is a huge list of features that has been introduced which I haven’t mentioned, so let me know in the discussion below which of the features I have missed and that you love the most in python. I hope you liked my blog and if this article adds any value then make sure to spread it with your friends and don’t forget to bookmark. If you have any questions, let me know via [Twitter](https://twitter.com/Yash_Makan) or in the discussion below. If you’d like more content like this, I post on [YouTube](https://www.youtube.com/@YashMakan) too. Till then b-bye!!