# 10 Things You Didn't Know You Could Do in Python3

> Lesser-known Python features that quietly make production code cleaner.

- Author: [Ashutosh Kumar](https://uncommonlydone.com/profile)
- Published: 2023-08-11 (first published on Medium · Python in Plain English: https://python.plainenglish.io/10-things-you-didnt-know-you-could-do-in-python3-99b7e38c5a3e)
- Also on: [DEV](https://dev.to/atkumar/10-things-you-didnt-know-you-could-do-in-python3-3196)
- Web page: https://uncommonlydone.com/blog/10-things-you-didnt-know-you-could-do-in-python3
- Tags: python

---

![Python code on a monitor, seen through a pair of glasses](https://uncommonlydone.com/blog/10-things-you-didnt-know-you-could-do-in-python3/01.webp)
_Photo by [Alex Chumak](https://unsplash.com/@ralexnder?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)_

Python is the third most commonly-used programming language. It has introduced many new features, simplifying and enhancing the development process. Yet, many developers remain unaware of the full potential that Python 3 has to offer.

This article will uncover ten lesser-known and underutilized capabilities in Python (v3.5 to v3.11). These hidden gems can improve your coding efficiency and productivity. So, without further ado, let’s dive into these fascinating Python 3 features.

## 1. Walrus Operator

It’s a new syntax introduced in [Python 3.11](https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions) that assigns values to variables as part of a larger expression.

Old way

```python
a = "This is a sample string text"

if len(a) > 10:
    print("Length of string a = ", len(a))
```

New way

```python
a = "This is a sample string text"

if (len_a := len(a)) > 10:  # Note the walrus operator will compute value of len(a) and assign it to variable len_a
    print("Length of string a = ", len_a)
```

## 2. Structural Pattern Matching

You might remember reading that Python doesn’t support switch statements because if-else can achieve the same result. You are in for a treat. [Python3.10](https://docs.python.org/3/whatsnew/3.10.html#simple-pattern-match-to-a-literal) introduced something similar.

Old way

```python
def http_error(status):
    if status == 400:
        return "Bad request"
    elif status == 404:
        return "Not found"
    elif status == 418:
        return "I'm a teapot"
    else:
        return "Something's wrong with the internet"
```

New way

```python
def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"
        case _:  # This is a wildcard operator
            return "Something's wrong with the internet"
```

## 3. Merging Dictionaries

[Python3.9](https://docs.python.org/3/whatsnew/3.9.html#dictionary-merge-update-operators) introduced a new way of merging or updating dictionaries. It complements the existing `dict.update` and `{**d1, **d2}` methods of merging dictionaries.

Old way

```python
x = {"key1": "value1 from x", "key2": "value2 from x"}
y = {"key2": "value2 from y", "key3": "value3 from y"}

print({**x, **y})
print({**y, **x})  # Note here keys of y would be given preference over keys of x
```

New way

```python
x = {"key1": "value1 from x", "key2": "value2 from x"}
y = {"key2": "value2 from y", "key3": "value3 from y"}

# Note the usage of OR (|) operator
print(x | y)
print(y | x)  # Note here keys of y would be given preference over keys of x
```

## 4. Removing Prefix or Suffix

[Python3.9](https://docs.python.org/3/whatsnew/3.9.html#new-string-methods-to-remove-prefixes-and-suffixes) introduced dedicated methods to get rid of prefixes or suffixes in strings.

Old way

```python
x = "prefixstring"
y = "stringsuffix"

print(x.split("prefix")[-1])
print(y.split("suffix")[0])
```

New way

```python
x = "prefixstring"
y = "stringsuffix"

print(x.removeprefix("prefix"))
print(y.removesuffix("suffix"))
```

## 5. Positional Only Parameters

Python provides to define positional and keyword arguments for a function. But you can pass them interchangeably. [Python3.8](https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters) introduced a way to enforce that you cannot pass positional arguments as keyword arguments.

Old way

```python
def fun(pos_arg1, pos_arg2, key_arg_1 = None):
    print("positional arguments: ", pos_arg1, pos_arg2)
    print("Keyword arguments: ", key_arg_1)

# It will work
fun(1, 2, 3)  # Passing keyword argument as positional argument

# It will also work
fun(pos_arg1=1, pos_arg2=2, key_arg_1=3)  # Passing positional argument as keyword argument
```

New way

```python
def fun(pos_arg1, pos_arg2, /, key_arg_1 = None):
    print("positional arguments: ", pos_arg1, pos_arg2)
    print("Keyword arguments: ", key_arg_1)

# It will work
fun(1, 2, 3)  # Passing keyword argument as positional argument

# It won't work
fun(1, pos_arg2=2, key_arg_1=3)  # Passing one positional argument as keyword argument
fun(pos_arg1=1, pos_arg2=2, key_arg_1=3)  # Passing both positional arguments as keyword argument
```

## 6. Time with nanoseconds Precision

Did you ever need nanosecond precision in getting time to compare code performances? [Python3.7](https://docs.python.org/3/whatsnew/3.7.html#pep-564-new-time-functions-with-nanosecond-resolution) introduced new methods in the time library.

Old way

```python
import time

start = time.time()
end = time.time()

print(end - start)
# Provides sub-second precision, though that precision varies by platform
# >> 2.7179718017578125e-05 Notice the precision is in e-05
```

New way

```python
import time

start = time.time_ns()
end = time.time_ns()

print(end - start)
# Provides nanosecond precision
# >> 47000 Notice the figure is in nanoseconds
```

## 7. f-Strings

[Python3.6](https://docs.python.org/3/whatsnew/3.6.html#pep-498-formatted-string-literals) introduced f-strings to provide an easy way of formatting strings.

Old way

```python
a = 1

print("Value of a = {}".format(a))
```

New way

```python
a = 1

print(f"Value of a = {a}")
```

## 8. Underscores in Numeric Literals

[Python 3.6](https://docs.python.org/3/whatsnew/3.6.html#pep-515-underscores-in-numeric-literals) introduced allowing adding underscores in numeric literals for better readability.

Old way

```python
a = 1000000000000000  # try counting the number of 0's

print(type(a))
# >> <class 'int'>
```

New way

```python
a = 1_000_000_000_000_000

print(type(a))
# >> <class 'int'>
```

## 9. Matrix Multiplication Operator

[Python3.5](https://docs.python.org/3/whatsnew/3.5.html#pep-465-a-dedicated-infix-operator-for-matrix-multiplication) introduced a dedicated @ infix operator for matrix multiplication.

Old way

```python
import numpy

x = numpy.ones(3)
m = numpy.eye(3)

print(x.dot(m))
```

New way

```python
import numpy  # NumPy 1.10 has support for the new operator:

x = numpy.ones(3)
m = numpy.eye(3)

print(x @ m)  # @ is the new matrix matrix-multiplication operator
```

## 10. Approximate Equality

[Python3.5](https://docs.python.org/3/whatsnew/3.5.html#pep-485-a-function-for-testing-approximate-equality) introduced dedicated methods to tell whether two values are approximately equal or “close” to each other.

Old way

```python
a = 5.0
b = 4.99998

print(abs(a - b) <= 1e-5)
```

New way

```python
import math

a = 5.0
b = 4.99998

print(math.isclose(a, b, rel_tol=1e-5))
```

## Resources

1. [Python3.11 Change-log](https://docs.python.org/3/whatsnew/3.11.html)
2. [Python3.10 Change-log](https://docs.python.org/3/whatsnew/3.10.html)
3. [Python3.9 Change-log](https://docs.python.org/3/whatsnew/3.9.html)
4. [Python3.8 Change-log](https://docs.python.org/3/whatsnew/3.8.html)
5. [Python3.7 Change-log](https://docs.python.org/3/whatsnew/3.7.html)
6. [Python3.6 Change-log](https://docs.python.org/3/whatsnew/3.6.html)
7. [Python3.5 Change-log](https://docs.python.org/3/whatsnew/3.5.html)
