Goodies of the Python Standard Library

The Python Standard Libary is part of your Python installation. It contains a wide range of packages which may be helpful while building your Python masterpieces. This notebook lists some of the commonly used packages and their main functionalities.

datetime for working with dates and times

In [1]:
import datetime as dt

local_now = dt.datetime.now()
print('local now: {}'.format(local_now))

utc_now = dt.datetime.utcnow()
print('utc now: {}'.format(utc_now))

# You can access any value separately:
print('{} {} {} {} {} {}'.format(local_now.year, local_now.month,
                                 local_now.day, local_now.hour,
                                 local_now.minute, local_now.second))

print('date: {}'.format(local_now.date()))
print('time: {}'.format(local_now.time()))
local now: 2018-09-19 22:44:15.396930
utc now: 2018-09-19 20:44:15.397085
2018 9 19 22 44 15
date: 2018-09-19
time: 22:44:15.396930

strftime()

For string formatting the datetime

In [2]:
formatted1 = local_now.strftime('%Y/%m/%d-%H:%M:%S')
print(formatted1)

formatted2 = local_now.strftime('date: %Y-%m-%d time:%H:%M:%S')
print(formatted2)
2018/09/19-22:44:15
date: 2018-09-19 time:22:44:15

strptime()

For converting a datetime string into a datetime object

In [3]:
my_dt = dt.datetime.strptime('2000-01-01 10:00:00', '%Y-%m-%d %H:%M:%S')
print('my_dt: {}'.format(my_dt))
my_dt: 2000-01-01 10:00:00

timedelta

For working with time difference.

In [4]:
tomorrow = local_now + dt.timedelta(days=1)
print('tomorrow this time: {}'.format(tomorrow))

delta = tomorrow - local_now
print('tomorrow - now = {}'.format(delta))
print('days: {}, seconds: {}'.format(delta.days, delta.seconds))
print('total seconds: {}'.format(delta.total_seconds()))
tomorrow this time: 2018-09-20 22:44:15.396930
tomorrow - now = 1 day, 0:00:00
days: 1, seconds: 0
total seconds: 86400.0

Working with timezones

Let's first make sure pytz is installed.

In [5]:
import sys
!{sys.executable} -m pip install pytz
Requirement already satisfied: pytz in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (2018.4)
In [6]:
import datetime as dt
import pytz

naive_utc_now = dt.datetime.utcnow()
print('naive utc now: {}, tzinfo: {}'.format(naive_utc_now, naive_utc_now.tzinfo))

# Localizing naive datetimes
UTC_TZ = pytz.timezone('UTC')
utc_now = UTC_TZ.localize(naive_utc_now)
print('utc now: {}, tzinfo: {}'.format(utc_now, utc_now.tzinfo))

# Converting localized datetimes to different timezone
PARIS_TZ = pytz.timezone('Europe/Paris')
paris_now = PARIS_TZ.normalize(utc_now)
print('Paris: {}, tzinfo: {}'.format(paris_now, paris_now.tzinfo))

NEW_YORK_TZ = pytz.timezone('America/New_York')
ny_now = NEW_YORK_TZ.normalize(utc_now)
print('New York: {}, tzinfo: {}'.format(ny_now, ny_now.tzinfo))
naive utc now: 2018-09-19 20:44:16.308229, tzinfo: None
utc now: 2018-09-19 20:44:16.308229+00:00, tzinfo: UTC
Paris: 2018-09-19 22:44:16.308229+02:00, tzinfo: Europe/Paris
New York: 2018-09-19 16:44:16.308229-04:00, tzinfo: America/New_York

NOTE: If your project uses datetimes heavily, you may want to take a look at external libraries, such as Pendulum and Maya, which make working with datetimes easier for certain use cases.

In [7]:
import logging

# Handy way for getting a dedicated logger for every module separately
logger = logging.getLogger(__name__)
logger.setLevel(logging.WARNING)

logger.debug('This is debug')
logger.info('This is info')
logger.warning('This is warning')
logger.error('This is error')
logger.critical('This is critical')
This is warning
This is error
This is critical

Logging expections

There's a neat exception function in logging module which will automatically log the stack trace in addition to user defined log entry.

In [8]:
try:
    path_calculation = 1 / 0
except ZeroDivisionError:
    logging.exception('All went south in my calculation')
ERROR:root:All went south in my calculation
Traceback (most recent call last):
  File "<ipython-input-8-ccd7d25e79b7>", line 2, in <module>
    path_calculation = 1 / 0
ZeroDivisionError: division by zero

Formatting log entries

In [9]:
import logging

# This is only required for Jupyter notebook environment
from importlib import reload
reload(logging)

my_format = '%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s'
logging.basicConfig(format=my_format)

logger = logging.getLogger('MyLogger')

logger.warning('Something bad is going to happen')
logger.error('Uups, it already happened')
2018-09-19 22:44:16,365 | MyLogger     | WARNING    | Something bad is going to happen
2018-09-19 22:44:16,366 | MyLogger     | ERROR      | Uups, it already happened

Logging to a file

In [10]:
import os
import logging

# This is only required for Jupyter notebook environment
from importlib import reload
reload(logging)

logger = logging.getLogger('MyFileLogger')

# Let's define a file_handler for our logger
log_path = os.path.join(os.getcwd(), 'my_log.txt')
file_handler = logging.FileHandler(log_path)

# And a nice format
formatter = logging.Formatter('%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s')
file_handler.setFormatter(formatter)

logger.addHandler(file_handler)

# If you want to see it also in the console, add another handler for it
# logger.addHandler(logging.StreamHandler())

logger.warning('Oops something is going to happen')
logger.error('John Doe visits our place')

random for random number generation

In [11]:
import random

rand_int = random.randint(1, 100)
print('random integer between 1-100: {}'.format(rand_int))

rand = random.random()
print('random float between 0-1: {}'.format(rand))
random integer between 1-100: 33
random float between 0-1: 0.10137384902353497

If you need pseudo random numbers, you can set the seed for random. This will reproduce the output (try running the cell multiple times):

In [12]:
import random

random.seed(5)  # Setting the seed

# Let's print 10 random numbers
for _ in range(10):
    print(random.random())
0.6229016948897019
0.7417869892607294
0.7951935655656966
0.9424502837770503
0.7398985747399307
0.922324996665417
0.029005228283614737
0.46562265437810535
0.9433567169983137
0.6489745531369242

re for regular expressions

Searching occurences

In [13]:
import re

secret_code = 'qwret 8sfg12f5 fd09f_df'
# "r" at the beginning means raw format, use it with regular expression patterns
search_pattern = r'(g12)' 

match = re.search(search_pattern, secret_code)
print('match: {}'.format(match))
print('match.group(): {}'.format(match.group()))

numbers_pattern = r'[0-9]'
numbers_match = re.findall(numbers_pattern, secret_code)
print('numbers: {}'.format(numbers_match))
match: <_sre.SRE_Match object; span=(9, 12), match='g12'>
match.group(): g12
numbers: ['8', '1', '2', '5', '0', '9']

Variable validation

In [14]:
import re

def validate_only_lower_case_letters(to_validate):
    pattern = r'^[a-z]+$'
    return bool(re.match(pattern, to_validate))

print(validate_only_lower_case_letters('thisshouldbeok'))
print(validate_only_lower_case_letters('thisshould notbeok'))
print(validate_only_lower_case_letters('Thisshouldnotbeok'))
print(validate_only_lower_case_letters('thisshouldnotbeok1'))
print(validate_only_lower_case_letters(''))
True
False
False
False
False