8. Built-in Functions and Types

There are many functions and types (data structures) that are built into Python that you should reuse and try to not re-invent yourself. As you progress and study more into Python, you will acquire exposure to ever more utility functions and data structures available. Below are just some samples of what we think will be useful.

8.1. Types

The function type() returns the type of a value or variable.

 1s = 'test'
 2i = 32
 3f = 32.2
 4b = False
 5
 6type_s = type(s)
 7type_i = type(i)
 8type_f = type(f)
 9type_b = type(b)
10
11print(type_s)
12print(type_i)
13print(type_f)
14print(type_b)

The following functions converts data from one type to another.

  • str() converts something into a string

  • int() converts something to an integer

  • float() converts something to a float

1a = str(32)
2b = int('32')
3c = float('32.2')
4
5print(a)
6print(b)
7print(c)

The function isinstance() checks to see if a variable/value is an instance of a particular type.

1a = isinstance('s', str)
2b = isinstance(3, int)
3c = isinstance(3.1415, float)
4d = isinstance(False, bool)
5
6print(a)
7print(b)
8print(c)
9print(d)

8.1.1. Exercise

Filter out the items in the list below for only integers, and create a new list from the integers.

1data = [1, 2, 'test', 3, 88, True, False, 32.2, 88.5, 0]

Solution.

1data = [1, 2, 'test', 3, 88, True, False, 32.2, 88.5, 0]
2numbers = [item for item in data if isinstance(item, int)]
3print(numbers)

8.2. Math

Use sum() to add up all the numbers in a collection.

1numbers = [23, 3, 5, 8]
2total = sum(numbers)
3
4print(total)

Use abs() to get the absolute value of a number.

1a = -9
2b = 9
3
4c = abs(a)
5d = abs(b)
6
7print(c)
8print(d)

Use min() and max() to find the minimum and maximum numbers in a collection, correspondingly.

1numbers = [23, 3, 5, -8, 100]
2
3smallest = min(numbers)
4largest = max(numbers)
5
6print(smallest)
7print(largest)

Use round() to round numbers to certain precisions (number of decimal places).

1a = 2.675255
2
3b = round(a, 1)
4c = round(a, 2)
5d = round(a, 3)
6
7print(b)
8print(c)
9print(d)

8.2.1. Exercise

The following is a list of lists. For each list, compute the average and store the averages into a new list.

1data = [
2    [10, 23, 88, 32, 343, 88, 77],
3    [22, 20, 18, 23, 45, 77, 88],
4    [55, 77, 32, 38, 67, 21, 33]
5]

Solution.

1data = [
2    [10, 23, 88, 32, 343, 88, 77],
3    [22, 20, 18, 23, 45, 77, 88],
4    [55, 77, 32, 38, 67, 21, 33]
5]
6
7averages = [sum(arr) / len(arr) for arr in data]
8print(averages)

8.3. Collections

The following functions create different collections.

  • list() creates an empty list or converts a collection into a list

  • set() creates an empty set or converts a collection into a set

  • tuple() creates an empty tuple or converts a collection into a tuple

  • dict() creates an empty dictionary

1a = set([1, 2, 3, 4, 5, 1, 3])
2b = tuple(a)
3c = list(b)
4
5print(a)
6print(b)
7print(c)

The function all() will return True if all the elements in a collection are not null e.g. None. The function any() will return True if at least one lement in a collection is not null e.g. None.

1numbers = [1, None, 2]
2
3print(all(numbers)) # False
4print(any(numbers)) # True

The function len() will return the number of elements in a collection.

1numbers = [1, None, 2]
2total = len(numbers)
3print(total)

The function sorted() sorts a collection in ascending order. The function reversed() reverse sorts a collection (descending order). Note that reversed() returns an iterator and not a collection, and so we convert that iterator to a list with list().

1numbers = [32, 33, 2, 88, 31, 3]
2
3print(sorted(numbers))
4print(list(reversed(numbers)))

8.3.1. Exercise

The following is a list of lists. For each sub-list, sort it into a new list. Your resulting list should be a list of sorted lists.

1data = [
2    [10, 23, 88, 32, 343, 88, 77],
3    [22, 20, 18, 23, 45, 77, 88],
4    [55, 77, 32, 38, 67, 21, 33]
5]

Solution.

1data = [
2    [10, 23, 88, 32, 343, 88, 77],
3    [22, 20, 18, 23, 45, 77, 88],
4    [55, 77, 32, 38, 67, 21, 33]
5]
6
7sorted_data = [sorted(arr) for arr in data]
8print(sorted_data)

8.4. Range

The range() function generates a range of values. To generate a range of numbers from [0, 9], we would do the following.

1numbers = list(range(10))
2print(numbers)

Note that range() does not create the numbers in the range until we start asking for the elements. range() is said to be a generator function. To get the actual numbers out, we have to convert the output of range() to a list.

We can specify the range of integers to output by supplying start and stop (exclusive) integers.

1numbers = list(range(10, 21))
2print(numbers)

We can also specify what number to increment the current number by to step over numbers.

1numbers = list(range(10, 21, 2))
2print(numbers)

8.4.1. Exercise

Generate a list of numbers from [0, 10] with only odd numbers.

Solution.

1numbers = [num for num in range(11) if num % 2 != 0]
2print(numbers)

8.5. random

Functions are also stored in built-in Python libraries (or modules). A library is just a collection of code that logically and/or conceptually belong together. To use these functions, we must import the function from the library. One built-in Python library is the random library, which deals with generating random numbers. Let’s see how we can import the randint() function.

1from random import randint

The syntax to import a function from a library is from <library> import <function>. After we import a function from a library, then we can use the function. The randint() function generates random number between two numbers (inclusive on both ends).

 1from random import randint
 2
 3# generate 3 random numbers in the range [0, 9]
 4a = randint(0, 9)
 5b = randint(0, 9)
 6c = randint(0, 9)
 7
 8print(a)
 9print(b)
10print(c)

The choice() function selects an element from a collection at random (all elements have an equal chance of being selected).

 1from random import choice
 2
 3numbers = [1, 2, 3, 4, 5, 6]
 4
 5a = choice(numbers)
 6b = choice(numbers)
 7c = choice(numbers)
 8
 9print(a)
10print(b)
11print(c)

The random() function generates a real number in the range [0, 1.0).

1from random import random
2
3a = random()
4b = random()
5c = random()
6
7print(a)
8print(b)
9print(c)

8.5.1. Exercise

Generate 10 random numbers in the range [0, 9].

Solution.

1from random import randint
2
3numbers = [randint(0, 9) for _ in range(10)]

8.5.2. Exercise

Generate 10 random numbers in the range [0, 9] only if the index associated with the random number is even.

Solution.

1from random import randint
2
3numbers = [randint(0, 9) for i, _ in enumerate(range(10)) if i % 2 == 0]
4print(numbers)

8.5.3. Exercise

Simulate rolling a die 1000 times. Each time you roll an even number, you win. How many times did you win?

Solution.

1from random import choice
2
3die = [1, 2, 3, 4, 5, 6]
4
5rolls = [choice(die) for _ in range(1000)]
6wins = sum([1 for roll in rolls if roll in {2, 4, 6}])
7print(wins)

8.5.4. Exercise

Simulate rolling two dice 1000. Each time you roll the dice and the sum of the outcomes is 7, you win. How many times did you win?

Solution.

1from random import choice
2
3die = [1, 2, 3, 4, 5, 6]
4
5rolls = [choice(die) + choice(die) for _ in range(1000)]
6wins = sum([1 for roll in rolls if roll == 7])
7print(wins)

8.6. itertools

Check out the itertools module. There are a lot of utility functions you can use to make working with collections easier. The cycle() function endlessly cycles through a list of elements. Imagine you have a list of people that you need to assign to two teams, Team Red and Team Blue. How can we assign the list of people to these two teams?

1from itertools import cycle
2
3colors = ['red', 'green']
4persons = ['Jack', 'John', 'Mary', 'Mandy', 'Moesha', 'Fatimah']
5
6teams = [(person, color) for person, color in zip(persons, cycle(colors))]
7print(teams)

What if we have a list of lists and wanted to flatten the list? Try the chain() function.

1from itertools import chain
2
3teams = [['Jack', 'Mary'], ['John', 'Moesha'], ['Mandy', 'Fatimah']]
4persons = list(chain(*teams))
5print(persons)

What if we have a list of names and we wanted to group them by the first letter of the name? The groupby() function will produce a key-value pair for us, where the key is what we want to group by and the value is an iterable.

1from itertools import groupby
2
3persons = ['Jack', 'Mary', 'John', 'Moesha', 'Mandy', 'Fatimah']
4
5by_first_letter = lambda name: name.lower()[0]
6name_map = {k: list(v) for k, v in groupby(persons, key=by_first_letter)}
7print(name_map)

If you have two lists and you want the resulting cross-product of the elements in those lists, try the product() function.

1from itertools import product
2
3products = list(product([1, 2, 3], ['A', 'B', 'C']))
4print(products)

What if you have a list of elements and you want the n permutations or combinations of elements from that list? In permutation, order is important, so a pair of number 2 and 3 is not the same as 3 and 2. In combination, order is not important, so 2 and 3 is the same as 3 and 2. Remember, a combination lock is a misnomer, and should be a permutation lock. At any rate, try permutations() and combinations().

1from itertools import combinations, permutations
2
3# [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
4print(list(permutations([1, 2, 3], 2)))
5
6# [(1, 2), (1, 3), (2, 3)]
7print(list(combinations([1, 2, 3], 2)))

8.6.1. Exercise

The Mega Millions is based on a player selecting 5 numbers from the range [1, 70] and one number from the range [1, 25]. How many combinations of numbers are possible?

Solution.

1from itertools import combinations, product
2
3white_nums = list(range(1, 71, 1))
4gold_nums = list(range(1, 26, 1))
5
6n = sum([1 for play in product(combinations(white_nums, 5), gold_nums)])
7print(f'{n:,}') # 302,575,350

8.6.2. Exercise

The Power Ball is based on a player selecting 5 numbers from the range [1, 69] and one number from the range [1, 26]. How many combinations of numbers are possible?

Solution.

1from itertools import combinations, product
2
3white_nums = list(range(1, 70, 1))
4red_nums = list(range(1, 27, 1))
5
6n = sum([1 for play in product(combinations(white_nums, 5), red_nums)])
7print(f'{n:,}') # 292,201,338

8.7. datetime

The datetime module has a lot of date functions and data structures (types) that we may use to speed up our ability to solve problems. Below, we show how to use the date type.

 1from datetime import date
 2
 3# create a date manually
 4d = date(2019, 10, 31)
 5print(d)
 6
 7# get the current date dynamically
 8d = date.today()
 9print(d)
10
11# get the date from a timestamp
12d = date.fromtimestamp(1555244364)
13print(d)
14
15# date difference
16a = date(2019, 10, 31)
17b = date(2019, 10, 30)
18diff = a - b
19print(diff)

The time type deals with the time.

1from datetime import time
2
3# create time manually
4t = time(11, 59, 59)
5print(t)
6
7# create time with microseconds
8t = time(11, 59, 59, 999999)
9print(t)

The datetime type (not the module) deals with both date and time.

 1from datetime import datetime
 2
 3# get the date-time now
 4dt = datetime.now()
 5print(dt)
 6
 7# create a date-time manually
 8dt = datetime(2019, 10, 31, 23, 55, 59, 100000)
 9print(dt)
10
11# create a date-time from a string
12# the date format code is available at https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
13# strptime stands for string parse time
14dt = datetime.strptime('2019-10-31 23:55:59.999999', '%Y-%m-%d %H:%M:%S.%f')
15print(dt)
16
17# formatting date-time
18# strftime stands for string format time
19s = datetime.strftime(dt, '%m-%d-%Y %H:%M:%S.%f %p')
20print(s)
21
22# subtract dates, datetime.timedelta
23a = datetime(2019, 10, 31, 23, 55, 59, 100)
24b = datetime(2018, 10, 31, 23, 55, 59, 100)
25c = a - b
26print(c)

The timedelta type enables us to do math operations on durations.

1from datetime import timedelta
2
3# compute difference between durations using timedelta
4a = timedelta(weeks=2, days=2, hours=1, seconds=30)
5b = timedelta(weeks=1, days=2, hours=1, seconds=30)
6diff = a - b
7print(diff)
8

The calendar module is very useful. We can use it to get the number of days for any particular month and year combination.

from calendar import monthrange

start, stop = monthrange(2011, 2)
print(f'start = {start}, stop = {stop}')

8.7.1. Exercise

Write a program to ask the user for a year. After you get the year:

  • print out the number of days per month for that year

  • print out the total number of days in that year

  • print out the total number of months with 31 days

  • print out the total number of months with even days

  • print out the total number of months with odd days

Solution.

from calendar import monthrange

year = int(input('year: '))

data = [(year, month, monthrange(year, month)[1]) for month in range(1, 13)]

print(f'number of days per month in {year}')
for y, m, d in data:
    print(f'{y}-{m}: {d}')

print('-' * 15)

n = sum([days for *_, days in data])
print(f'total days in {year}: {n}')

print('-' * 15)

n = sum([1 for *_, days in data if days == 31])
print(f'total months in {year} with 31 days: {n}')

print('-' * 15)

n = sum([1 for *_, days in data if days % 2 == 0])
print(f'total months in {year} with even total number of days: {n}')

print('-' * 15)

n = sum([1 for *_, days in data if days % 2 != 0])
print(f'total months in {year} with odd total number of days: {n}')

8.8. pathlib

For interacting with files, try the pathlib module. Below, we create a collection of all Python files.

1import pathlib
2
3py_files = pathlib.Path('../').glob('**/*.py')
4
5for f in py_files:
6    print(f)

8.9. urllib

If you need to interact with websites, try the urllib module.

 1import urllib.request
 2import urllib.parse
 3
 4# simple request
 5with urllib.request.urlopen('https://www.oneoffcoder.com/') as response:
 6    content = response.read()
 7    print(content)
 8
 9# request with query string parameters
10query_string_data = {
11    'q': 'oneoffcoder',
12    'sourceid': 'chrome',
13    'ie': 'UTF-8'
14}
15query_string = urllib.parse.urlencode(query_string_data)
16url = f'https://www.google.com/search?{query_string}'
17data = urllib.request.urlopen(url)
18
19# request with headers
20query_string_data = {
21    'q': 'oneoffcoder',
22    'sourceid': 'chrome',
23    'ie': 'UTF-8'
24}
25query_string = urllib.parse.urlencode(query_string_data).encode('ascii')
26
27headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)'}
28url = 'https://www.google.com/search'
29
30req = urllib.request.Request(url, data, headers)
31with urllib.request.urlopen(req) as response:
32    content = response.read()

8.9.1. Exercise

Write a program to get the contents of https://www.oneoffcoder.com. How many times did the vowels a, e, i, o and u appear?

Solution.

import urllib.request

vowels = {'a', 'e', 'i', 'o', 'u'}

with urllib.request.urlopen('https://www.oneoffcoder.com/') as response:
    content = response.read()

    n = sum([1 for letter in content if chr(letter) in vowels])
    print(f'total vowels: {n}')

8.9.2. Exercise

Write a program to get the contents of https://www.oneoffcoder.com.

  • What is the number of times the each character in the range [a, z] appeared?

  • What is the number of times each special characters (characters not in the range [a, z]) appeared?

Solution.

import urllib.request
from itertools import groupby
import string

letters = set(list(string.ascii_lowercase))

with urllib.request.urlopen('https://www.oneoffcoder.com/') as response:
    content = response.read().lower()

    is_valid = lambda letter: chr(letter) in letters
    get_key = lambda letter: letter

    # letters in [a, z]
    counts = sorted([chr(letter) for letter in content if is_valid(letter)], key=get_key)

    for k, v in groupby(counts, key=get_key):
        print(f'{k} => {len(list(v))}')

    print('-' * 15)

    # special characters not in [a, z]
    counts = sorted([chr(letter) for letter in content if not is_valid(letter)], key=get_key)

    for k, v in groupby(counts, key=get_key):
        print(f'{k} => {len(list(v))}')