Open In Colab

Lesson 10: Functional Programming

Pragmatic AI Labs

alt text

This notebook was produced by Pragmatic AI Labs. You can continue learning about these topics by:

10.1 Understand functional programming

Depending on state

wind = 'Southeast'

def describe_the_wind():
  return f'The wind blows from the {wind}'

describe_the_wind()
'The wind blows from the Southeast'

Functional approach

def describe_the_wind(wind):
  return f'The wind blows from the {wind}'

describe_the_wind('Northeast')
'The wind blows from the Northeast'

Changing state

WINDS = ['Northeast', 'Northwest', 'Southeast', 'Southwest']
WIND = WINDS[0]

def change_wind():
  global WIND
  WIND = WINDS[(WINDS.index(WIND) + 1)%3]
  
WIND
'Northeast'
change_wind()
WIND
'Northeast'
for _ in WINDS:
  print(WIND)
  change_wind()

Functional approach

def change_wind(wind_index):
  winds = ['Northeast', 'Northwest', 'Southeast', 'Southwest']
  return winds[wind_index]

print( change_wind(0) )
print( change_wind(1) )
print( change_wind(2) )
print( change_wind(3) )
Northeast
Northwest
Southeast
Southwest

Changing state

def change_mutable_data(data):
  '''A function which changes
  mutable data.'''
  data['owner'] = 'White Star Line'

  
d = {"vehicle": "ship", "owner": "Joseph Bruce Ismay"}

change_mutable_data(d)
d

{'owner': 'White Star Line', 'vehicle': 'ship'}

Functional approach

d = {"vehicle": "ship", "owner": "Joseph Bruce Ismay"}

def change_owner(data):
  new_data = data.copy()
  new_data['owner'] = 'White Star Line'
  return new_data


changed = change_owner(d)
changed
{'owner': 'White Star Line', 'vehicle': 'ship'}

10.2 Apply functions to data science workflows

import pandas as pd
moby_dick_quotes = [
    """It is not down on any map; true places never are.""",
    """
    Consider the subtleness of the sea; how its most dreaded creatures glide under water, unapparent for the most part, and treacherously hidden beneath the loveliest tints of azure. Consider also the devilish brilliance and beauty of many of its most remorseless tribes, as the dainty embellished shape of many species of sharks. Consider, once more, the universal cannibalism of the sea; all whose creatures prey upon each other, carrying on eternal war since the world began. 
    Consider all this; and then turn to the green, gentle, and most docile earth; consider them both, the sea and the land; and do you not find a strange analogy to something in yourself? For as this appalling ocean surrounds the verdant land, so in the soul of man there lies one insular Tahiti, full of peace and joy, but encompassed by all the horrors of the half-known life. God keep thee! Push not off from that isle, thou canst never return!
    """,
    """
    The sea had jeeringly kept his finite body up, but drowned the infinite of his soul. Not drowned entirely, though. Rather carried down alive to wondrous depths, where strange shapes of the unwarped primal world glided to and fro before his passive eyes; and the miser-merman, Wisdom, revealed his hoarded heaps; and among the joyous, heartless, ever-juvenile eternities, Pip saw the multitudinous, God-omnipresent, coral insects, that out of the firmament of waters heaved the colossal orbs. He saw God’s foot upon the treadle of the loom, and spoke it; and therefore his shipmates called him mad. So man’s insanity is heaven’s sense; and wandering from all mortal reason, man comes at last to that celestial thought, which, to reason, is absurd and frantic; and weal or woe, feels then uncompromised, indifferent as his God.
    """
]
df = pd.DataFrame(moby_dick_quotes)
df.columns = ["quotes"]
df.head()
quotes
0 It is not down on any map; true places never are.
1 \n Consider the subtleness of the sea; how ...
2 \n The sea had jeeringly kept his finite bo...
def classify_religious(column):
  """Creates Religion Feature"""
  
  if "God" in column:
    return "Religious"
  return "Secular"

df["quote_type"] = df["quotes"].apply(classify_religious)
df.head()
  
quotes quote_type
0 It is not down on any map; true places never are. Secular
1 \n Consider the subtleness of the sea; how ... Religious
2 \n The sea had jeeringly kept his finite bo... Religious

10.3 Use map/reduce/filter

map

def count_flower_petals(d):
  return f"{d} petals counted so far"

counts = map(count_flower_petals, [0,1,2,3,4,5])


list(counts)
['0 petals counted so far',
 '1 petals counted so far',
 '2 petals counted so far',
 '3 petals counted so far',
 '4 petals counted so far',
 '5 petals counted so far']

mapping with multiple inputs

l1 = [0,1,2,3,4]
l2 = [10,9,8,7,6]

def multi(d1, d2):
  return d1 * d2

result = map(multi, l1, l2)
print( list(result) )
[0, 9, 16, 21, 24]

reduce

initial_balance = 10000
debits = [20, 40, 300, 3000, 1, 234]


balance = initial_balance

for debit in debits:
  balance -= debit
  
balance

6405
inital_balance = 10000
debits = [20, 40, 300, 3000, 1, 234]
from functools import reduce

def minus(a, b):
  return a - b

balance = reduce(minus, debits, initial_balance)
balance
6405
inital_balance = 10000
debits = [20, 40, 300, 3000, 1, 234]

from functools import reduce
import operator

print( reduce(operator.sub, debits, initial_balance) )
6405

filter

characters = ['C', 'b', 'c', 'A', 'b','P', 'g', 'S']

def cap(a):
  return a.isupper()

retval = filter(cap, characters)

list(retval)
['C', 'A', 'P', 'S']

10.4 Use list comprehensions

For loop

names = ['tim', 'tiger', 'tabassum', 'theodora', 'tanya']

capd = []

for name in names:
  capd.append(name.title())
  
capd
['Tim', 'Tiger', 'Tabassum', 'Theodora', 'Tanya']

Basic list comprehension

names = ['tim', 'tiger', 'tabassum', 'theodora', 'tanya']

capd = [x.title() for x in names]

capd
['Tim', 'Tiger', 'Tabassum', 'Theodora', 'Tanya']

Mapping

map example
def count_flower_petals(d):
  return f"{d} petals counted so far"

counts = map(count_flower_petals, [0,1,2,3,4,5])

list(counts)
['0 petals counted so far',
 '1 petals counted so far',
 '2 petals counted so far',
 '3 petals counted so far',
 '4 petals counted so far',
 '5 petals counted so far']
mapping using list comprehension
[f"{x} petals counted so far" for x in [0,1,2,3,4,5]]
['0 petals counted so far',
 '1 petals counted so far',
 '2 petals counted so far',
 '3 petals counted so far',
 '4 petals counted so far',
 '5 petals counted so far']

Filtering

filter function
characters = ['C', 'b', 'c', 'A', 'b','P', 'g', 'S']

def cap(a):
  return a.isupper()

retval = filter(cap, characters)

list(retval)
['C', 'A', 'P', 'S']
filtering in list comprehension
characters = ['C', 'b', 'c', 'A', 'b','P', 'g', 'S']

[x for x in characters if x.isupper()]
['C', 'A', 'P', 'S']

Multiple variables

horts = [ 32.0, 54.12, 12.4, 89.09]
verts = [ 15.9, -34.21, 45.54, 90]

[ f'x: {x} y: {y}' for x,y in zip(horts, verts) ]
['x: 32.0 y: 15.9', 'x: 54.12 y: -34.21', 'x: 12.4 y: 45.54', 'x: 89.09 y: 90']
list(zip(horts, verts))
[(32.0, 15.9), (54.12, -34.21), (12.4, 45.54), (89.09, 90)]

Flatten a list of lists

list_of_lists = [[1,2,3], [4,5,6], [7,8,9]]


[x for y in list_of_lists for x in y]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Nested

# Integers greater than and with 3 as a factor divided by 2


[y for y in range(20)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[y for y in range(20) if y%3==0]
[0, 3, 6, 9, 12, 15, 18]
[x//2 for x in [y for y in range(20) if y%3==0] if x > 3]
[3, 4, 6, 7, 9]

10.5 Use dictionary comprehensions

rows = [{'name': 'barry', 'id': 1},
        {'name': 'henry', 'id': 3},
        {'name': 'suzy', 'id': 2}]

{ x['name']: x['id'] for x in rows}

{'barry': 1, 'henry': 3, 'suzy': 2}

Notes

Functional Programming

Functional Programming Python