0% found this document useful (0 votes)
55 views37 pages

Functions As Objects, Dictionaries

The document discusses functions as objects in Python. It notes that functions are first-class objects that can be treated like other objects like strings and lists. Functions can be elements of data structures and appear in expressions. This allows higher-order functions where functions are passed as arguments to other functions. Examples show a function that applies another function to each element of a list, mutating the list. Map is also discussed as a general purpose function that applies a function to each element of a list or multiple lists. Finally, dictionaries are introduced as a cleaner way to associate data compared to separate lists. Dictionaries allow looking up values using keys rather than indices.

Uploaded by

Perry Ho
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
55 views37 pages

Functions As Objects, Dictionaries

The document discusses functions as objects in Python. It notes that functions are first-class objects that can be treated like other objects like strings and lists. Functions can be elements of data structures and appear in expressions. This allows higher-order functions where functions are passed as arguments to other functions. Examples show a function that applies another function to each element of a list, mutating the list. Map is also discussed as a general purpose function that applies a function to each element of a list or multiple lists. Finally, dictionaries are introduced as a cleaner way to associate data compared to separate lists. Dictionaries allow looking up values using keys rather than indices.

Uploaded by

Perry Ho
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 37

FUNCTIONS AS

OBJECTS,
DICTIONARIES

6.00.1X LECTURE 1
FUNCTIONS AS OBJECTS
 functions are first class objects:
◦ have types
◦ can be elements of data structures like lists
◦ can appear in expressions
◦ as part of an assignment statement
◦ as an argument to a function!!

 particularly useful to use functions as arguments


when coupled with lists
◦ aka higher order programming using functions inside of lists to do things on lists

Functions can be used in same places we would use numbers or strings or lists.
Functions can be elements of a data structure and can appear inside expressions. Same thing as strings.
EXAMPLE
def applyToEach(L, f):
"""assumes L is a list, f a function
mutates L by replacing each element,
e, of L by f(e)"""
for i in range(len(L)):
L[i] = f(L[i])
For each index that goes into the list, get out the element of hte list, apply f to it, and then put that back int that spot inside of the
list. You are mutating the list as you do it.
EXAMPLE
def applyToEach(L, f):
for i in range(len(L)):
L[i] = f(L[i])
L = [1, -2, 3.4]
applyToEach(L, abs)

applyToEach(L, int)

applyToEach(L, fact)

applyToEach(L, fib)
EXAMPLE
def applyToEach(L, f):
for i in range(len(L)):
L[i] = f(L[i])
L = [1, -2, 3.4]
applyToEach(L, abs)
[1, 2, 3.4]
applyToEach(L, int)

applyToEach(L, fact)

applyToEach(L, fib)
EXAMPLE
def applyToEach(L, f):
for i in range(len(L)):
L[i] = f(L[i])
L = [1, -2, 3.4]
applyToEach(L, abs)
[1, 2, 3.4]
applyToEach(L, int)
[1, 2, 3]
applyToEach(L, fact)

applyToEach(L, fib)
EXAMPLE
def applyToEach(L, f):
for i in range(len(L)):
L[i] = f(L[i])
L = [1, -2, 3.4]
applyToEach(L, abs)
[1, 2, 3.4]
applyToEach(L, int)
[1, 2, 3]
applyToEach(L, fact)
[1, 2, 6]
applyToEach(L, fib)
Now you can think of doing something to each element of the list.

Apply to each is literally saying, given a data structure, give me


back the data structure where i've done something to each
element of the list.

EXAMPLE
def applyToEach(L, f):
for i in range(len(L)):
L[i] = f(L[i])
L = [1, -2, 3.4]
applyToEach(L, abs)
[1, 2, 3.4]
applyToEach(L, int)
[1, 2, 3]
applyToEach(L, fact) applying factorial to each element of the list

[1, 2, 6]
applyToEach(L, fib)
[1, 2, 13]
LISTS OF FUNCTIONS
def applyFuns(L, x): assumes L is a list of functions.

for f in L: For element in eac

print(f(x))

applyFuns([abs, int, fact, fib], 4)


4 abs of 4
4 int of 4
24 factorial of 4
5 fibonacci of 4
map takes a function that has only one argument, and a list of appropriate arguments.

and it creates a list where it has applied that function to each element in turn.

GENERALIZATION OF HOPS (higher order procedure)

 Python provides a general purpose HOP, map


 simple form – a unary function and a collection of suitable arguments
◦ map(abs, [1, -2, 3, -4])
 produces an ‘iterable’, so need to walk down it
for elt in map(abs, [1, -2, 3, -4]):
print(elt)
[1, 2, 3, 4] previously, mutating a list. Map is different.

map gives you back a structure that that is going to act like a list, but it's something you have to iterate to get it out.

 general form – an n-ary function and n collections of arguments


◦ L1 = [1, 28, 36] with two lists, can map a function down those pairs of lists and generates for us
◦ L2 = [2, 57, 9] something that has the result of doing that processing.

for elt in map(min, L1, L2):


print(elt)
[1, 28, 9]
6.00.1X LECTURE 11
STRINGS, TUPLES, RANGES,
LISTS all 4 are very similar to one another and can do similar things

 Common operations
◦ seq[i]  ith element of sequence
◦ len(seq)  length of sequence
◦ seq1 + seq2  concatenation of sequences (not range)
◦ n*seq  sequence that repeats seq n times (not range)
◦ seq[start:end]  slice of sequence
◦ e in seq  True if e contained in sequence
◦ e not in seq  True if e contained in sequence
◦ for e in seq  iterates over elements of sequence

6.00.1X LECTURE 12
String - concatenation of characters
Tuple - concatenation of any type of object
Note: only the List is mutable. Range - concatenation of a sequence (i.e. integers)
List - a sequence of any kind of object

PROPERTIES
Type Type of Examples of literals Mutable
elements
str characters ‘ ‘, ‘a’, No
‘abc’
tuple any type (), (3,), No
(‘abc’, 4)
range integers range(10), No
range(1,10,2)
list any type [], [3], Yes
[‘abc’, 4]
6.00.1X LECTURE 13
6.00.1X LECTURE 14
DICTIONARIES
So far, we've introduced Lists and Tuples, Mutables vs. Immutables.

6.00.1X LECTURE 15
HOW TO STORE
STUDENT INFO
 so far, can store using separate lists for every info
names = ['Ana', 'John', 'Denise', 'Katy'] ex. storing student data in a
database
grade = ['B', 'A+', 'A', 'A']
course = [2.00, 6.0001, 20.002, 9.01]

 a separate list for each item


 each list must have the same length so you can associate pieces together
 info stored across lists at same index, each index
refers to info for a different person
Issue is that you need to be able to associate all of those pieces together. Each index stores information for a different person.

6.00.1X LECTURE 16
HOW TO UPDATE/RETRIEVE
STUDENT INFO
def get_grade(student, name_list, grade_list, course_list):
i = name_list.index(student) Find the index of that student

grade = grade_list[i] Then, find that students index in the grade list

course = course_list[i]
return (course, grade)

 messy if have a lot of different info to keep track of


 must maintain many lists and pass them as arguments
 must always index using integers this way is very inconvenient

 must remember to change multiple lists


6.00.1X LECTURE 17
A BETTER AND CLEANER WAY –
A DICTIONARY
 nice to index item of interest directly (not always int)
 nice to use one data structure, no separate lists
A list A dictionary
0 Elem 1 Key 1 Val 1 In a dictionary,
rather than saying,
give me the zeroth
1 Elem 2 Key 2 Val 2 element, you will say
"give me the element
associate with this
2 Elem 3 Key 3 Val 3 key"

3 Elem 4 Key 4 Val 4 So, we will call the


indices key to use
them as labels that
… … … … tell you where to
find the element
inside of the
dictionary

6.00.1X LECTURE 18
A PYTHON DICTIONARY
 store pairs of data 'Ana'
Key 1 'B'1
Val
• key Key = the thing to look up 'Denise'
Key 2 'A'2
Val
• value
'John'
Key 3 'A+'
Val 3

'Katy'
… 'A'

my_dict = {} Note, now we use curly brackets to represent a dictionary

grades = {'Ana':'B', 'John':'A+', 'Denise':'A', 'Katy':'A'}

key1 val1 key2 val2 key3 val3 key4 val4


Each one is an association pairing of key or value
6.00.1X LECTURE 19
DICTIONARY LOOKUP
 similar to indexing into a list 'Ana' 'B'

 looks up the key 'Denise' 'A'

 returns the value associated 'John' 'A+'


with the key 'Katy' 'A'

 if key isn’t found, get an error

grades = {'Ana':'B', 'John':'A+', 'Denise':'A', 'Katy':'A'}


grades['John']  evaluates to 'A+'
grades['Sylvan']  gives a KeyError

6.00.1X LECTURE 20
'Ana' 'B'
DICTIONARY 'Denise' 'A'

OPERATIONS 'John' 'A+'

'Katy' 'A'

'Sylvan' 'A'

grades = {'Ana':'B', 'John':'A+', 'Denise':'A', 'Katy':'A'}

 add an entry
grades['Sylvan'] = 'A'
 test if key in dictionary
'John' in grades  returns True
'Daniel' in grades  returns False
 delete entry
del(grades['Ana'])

6.00.1X LECTURE 21
'Ana' 'B'
DICTIONARY 'Denise' 'A'

OPERATIONS 'John' 'A+'

'Katy' 'A'

grades = {'Ana':'B', 'John':'A+', 'Denise':'A', 'Katy':'A'}

 get an iterable that acts like a tuple of all keys


grades.keys()  returns ['Denise','Katy','John','Ana']

get an iterable that acts like a tuple of all values


grades.values()  returns ['A', 'A', 'A+', 'B']
Note: cannot guarantee there is a particular order. It depends how you put it in there.

6.00.1X LECTURE 22
The values that go into dictionary can be any type.

DICTIONARY KEYS and VALUES


 values
• any type (immutable and mutable)
• can be duplicates
• dictionary values can be lists, even other dictionaries!
 keys
• must be unique
• immutable type (int, float, string, tuple,bool)
• actually need an object that is hashable, but think of as immutable as all
immutable types are hashable
• careful with float type as a key if float has accuracy issue, you may not be able to find
what you need

 no order to keys or values!


d = {4:{1:0}, (1,3):"twelve", 'const':[3.14,2.7,8.44]}
6.00.1X LECTURE 23
list vs dict
 ordered sequence of  matches “keys” to
elements “values”
 look up elements by an  look up one item by
integer index another item
 indices have an order  no order is guaranteed
 index is an integer  key can be any
- They are ordered so therefore you can get an index immutable type
lookup out of it
- just a collection of entries and you match keys to values

6.00.1X LECTURE 24
6.00.1X LECTURE 25
EXAMPLE: 3 FUNCTIONS TO
ANALYZE SONG LYRICS
1) create a frequency dictionary mapping str:int
2) find word that occurs the most and how many times
• use a list, in case there is more than one word
• return a tuple (list,int) for (words_list, highest_freq)
3) find the words that occur at least X times
• let user choose “at least X times”, so allow as parameterS
• return a list of tuples, each tuple is a (list, int)
containing the list of words ordered by their frequency
• IDEA: From song dictionary, find most frequent word. Delete
most common word. Repeat. It works because you are
mutating the song dictionary.
6.00.1X LECTURE 26
CREATING A DICTIONARY lyrics is a string of
words separated by
spaces

def lyrics_to_frequencies(lyrics):
myDict = {}
for word in lyrics:
if word in myDict:
myDict[word] += 1
else:
myDict[word] = 1
if word not in dictionary, set value corresponding to that word to 1
return myDict

6.00.1X LECTURE 27
USING THE DICTIONARY
def most_common_words(freqs):
values = freqs.values()
best = max(values) in 2 lines, give me the
values in the dictionary.

words = [] we could also write a long


iterable, but it's a lot of
for k in freqs: code

if freqs[k] == best: i.e. is it one of the most common words


words.append(k) add it to the end of the list
return (words, best)

6.00.1X LECTURE 28
LEVERAGING DICTIONARY
PROPERTIES
def words_often(freqs, minTimes):
result = []
done = False
while not done:
temp = most_common_words(freqs)
if temp[1] >= minTimes:
result.append(temp)
for w in temp[0]:
given i've done the analysis, find the
del(freqs[w]) most common word.
else:
If it occurs more than minimum what
done = True i've set, then collect them, and then
return result remove them from the dictionary. So we
are mutating the dictionary.

Keep doing it until when you pull out


the most common word that doesn't
print(words_often(beatles, 5)) exceed threshold, then set that value to
true.

6.00.1X LECTURE 29
6.00.1X LECTURE 30
FIBONACCI RECURSIVE CODE
def fib(n):
if n == 1:
return 1
elif n == 2:
return 2
else:
return fib(n-1) + fib(n-2)
 two base cases
 calls itself twice
 this code is inefficient

6.00.1X LECTURE 31
INEFFICIENT FIBONACCI
fib(n) = fib(n-1) + fib(n-2)
fib(5)

fib(4) fib(3)

you didn't really need to do


fib(3) fib(3). The calculation was
fib(2) fib(2) fib(1) already done in fib(4).

it will slow down when


trying to do large Fibonacci
fib(2) fib(1) numbers

 recalculating the same values many times! This is how dictionaries help
 could keep track of already calculated values
6.00.1X LECTURE 32
FIBONACCI WITH A
DICTIONARY
def fib_efficient(n, d): calculate the nth fibonacci but give it a dictionary
if n in d: if i've already done the work, just look it up and return it
return d[n]
else:
ans = fib_efficient(n-1, d) + fib_efficient(n-2, d)
d[n] = ans
return ans

d = {1:1, 2:2}
print(fib_efficient(6, d))

you can use the dictionary to hold on to values you've already computed and you don't need to recompute

 do a lookup first in case already calculated the value


 modify dictionary as progress through function calls
6.00.1X LECTURE 33
6.00.1X LECTURE 34
Global Variables allow you to move variables out of scope.

But it will result in side effects.

GLOBAL VARIABLES
 can be dangerous to use can really lead to side effects in a bad way

◦ breaks the scoping of variables by function call


◦ allows for side effects of changing variable values in ways
that affect other computation
 but can be convenient when want to keep track of
information inside a function

 example – measuring how often fib and


fib_efficient are called

6.00.1X LECTURE 35
Before, anything inside function only accessible inside the call of the function itself.

global --> allows accessibility outside the scope of the function as well

TRACKING EFFICIENCY
def fib(n): def fibef(n, d):
global numFibCalls global numFibCalls
numFibCalls += 1 numFibCalls += 1
if n == 1: if n in d:
return 1 return d[n]
elif n == 2: else:
ans = fibef(n-1,d)+fibef(n-2,d)
return 2
d[n] = ans
else:
return ans
return fib(n-1)+fib(n-2)

6.00.1X LECTURE 36
Comparing efficiency of Fib vs Fib_efficient

TRACKING EFFICIENCY
numFibCalls = 0 initialize the global variable outside

print(fib(12))
print('function calls', numFibCalls)
287 calls with fib

numFibCalls = 0

d = {1:1, 2:2}
print(fib_efficient(12, d))
print('function calls', numFibCalls)
only 21 calls with fib_efficient

As a result: Dictionaries can be very handy and can help more efficiently capture information

6.00.1X LECTURE 37

You might also like