10.2. Utilities for Python#

10.2.1. Speed up For-Loop with joblib.Parallel#

Don’t use plain for loops in Python.

Joblib provides a Parallel class to write parallel for loops using multiprocessing.

Below you can see an example of how to use it with all of your processors to speed up your calculations.

from joblib import Parallel, delayed

def process_image(path):
   ...
    return image
  
 image_paths = ["path1.jpg", "path2.jpg"]

result = Parallel(n_jobs = -1, backend = "multiprocessing")(
  delayed(process_image)(path) for path in image_paths
)

10.2.2. Work with datetimes easily with pendulum#

Tired of the difficulties of working with dates and times in Python?

Try pendulum!

pendulum takes the built-in datetime library from Python to the next level with its intuitive and human-friendly way of handling dates and times.

This includes easy timezone manipulation, daylight saving time calculations, and more!

#!pip install pendulum
import pendulum

dt = pendulum.now()
print(dt.to_iso8601_string())
# Output: 2023-02-08T13:44:23.798316+01:00

now_in_london = pendulum.now('Europe/London')
print(now_in_london)
# Output: 2023-02-08T12:44:23.799317+00:00

past = pendulum.now().subtract(minutes=8)
print(past.diff_for_humans())
# Output: 8 minutes ago

delta = past - pendulum.now().subtract(weeks=1)
print(delta.in_words())
# Output: 6 days 23 hours 51 minutes 59 seconds

10.2.3. Prettify your Data Structures with pprint#

Using print() on your data structures can give you ugly outputs.

With pprint, you can print data structures in a pretty way

Don’t use plain print() for printing data structures anymore.

from pprint import pprint

data = [ (i, { 'a':'A',
               'b':'B',
               'c':'C',
               'd':'D',
               'e':'E',
               'f':'F',
               'g':'G',
               'h':'H',
               })
         for i in range(2)
         ]
         
pprint(data)

10.2.4. Easy Logging with loguru#

Are you too lazy for logging?

loguru makes logging in Python easy.

It comes with pre-built formats and colors so you don’t have to set them manually.

A more elegant alternative to Python’s standard logging module.

from loguru import logger

def main():
    logger.debug("DEBUG message")
    logger.info("INFO message")
    logger.warning("WARNING message")
    logger.error("ERROR message")
    logger.critical("CRITICAL message")


if __name__ == '__main__':
    main()

10.2.5. Generate Truly Random Numbers#

How to generate truly random numbers?

One problem with random number generators in your favourite programming language is:

They are pseudo-random.

That means they are generated using a deterministic algorithm.

If you want to generate truly random numbers,

You have to make an API request to random(dot)org.

They create random numbers based on atmospheric noise.

See below how you can use it with Python.

What do the Query Parameters mean?

  • num=1: Specifies that only one integer should be generated.

  • min=1: Specifies that the minimum value for the generated integer should be 1.

  • max=1000: Specifies that the maximum value for the generated integer should be 1000.

  • col=1: Specifies that the output should be in a single column. Only useful for displaying purposes when you are generating more than one number.

  • base=10: Specifies that the generated integers should be in base 10 (decimal).

  • format=plain: Specifies that the output should be in plain text format.

  • rnd=new: Specifies that a new random sequence should be used for each request.

import requests

url = "https://www.random.org/integers/?num=1&min=1&max=1000&col=1&base=10&format=plain&rnd=new"

response = requests.get(url)
print(response.text)

10.2.6. Powerful Dictionaries with python-benedict#

python-benedict is a library for dictionaries on steroids.

You can access values of your nested dictionary with a neat syntax, perform searching and GroupBy, and much more.

Of course, Pandas offers similar functionalities, but takes also much memory when installing. But 𝐩𝐲𝐭𝐑𝐨𝐧-π›πžπ§πžππ’πœπ­ is more suitable for more unstructured data.

!pip install python-benedict
from benedict import benedict

my_dict = benedict({
    'person': {
        'name': 'John',
        'age': 25,
        'address': {
            'street': '123 Main St',
            'city': 'New York',
            'country': 'USA'
        }
    }
})

my_dict.get("person.address.street")

my_dict.flatten()

10.2.7. Clear Exception Output with pretty_errors#

Are you annoyed by the unclear Python error messages?

Try pretty_errors.

It’s a library to prettify Python exception output to make it more readable and clear.

It also allows you to configure the output like changing colors, separator character, displaying locals, etc..

You just have to:

Install it: pip install pretty_errors Import it: import pretty_errors.

!pip install pretty_errors
import pretty_errors

num = 1 / 0

10.2.8. Deprecate Functions with deprecated#

How to deprecate functions in Python?

You can use the library deprecation which offers decorators to wrap functions.

Proper warnings in documentation and in the console are displayed.

!pip install deprecation
from deprecation import deprecated

@deprecated(deprecated_in="0.10", removed_in="1.0", current_version=__version__, details="Use my_func2 instead")
def my_func():
  print("Hello World")
  
my_func()
# UnsupportedWarning: my_func is unsupported as of 1.0. Use my_func2 instead

10.2.9. Case Insensitive Dictionaries#

Are you annoyed by case-sensitive dictionaries in Python?

Try π‚πšπ¬πžπˆπ§π¬πžπ§π¬π’π­π’π―πžπƒπ’πœπ­π¬.

As the name says, you can access values by the key without paying attention to lowercase or uppercase.

It’s useful for everyone who is scraping API data.

from requests.structures import CaseInsensitiveDict

data: dict[str, str | int] = CaseInsensitiveDict(
    {
        "accept": "application/json",
        "content-type": "application/json",
        "User-Agent": "Mozilla/5.0",
    }
)

print(data.get("Accept"))