You are on page 1of 84

DECOMPOSITION,

ABSTRACTION,
FUNCTIONS

February 22, 2016 6.0001 LECTURE 6 1


HOW DO WE WRITE CODE?
 so far…
• covered language mechanisms i.e. for and while loops
• know how to write different files for each computation
• each file is some piece of code
• each code is a sequence of instructions
 problems with this approach
• easy for small-scale problems but doesn't scale very nicely.
• messy for larger problems
• hard to keep track of details
• how do you know the right info is supplied to the right
part of code
February 22, 2016 6.0001 LECTURE 6 2
Good programming is more than just adding more code.

GOOD PROGRAMMING
 more code not necessarily a good thing
 measure good programmers by the amount of
functionality
 introduce functions Functions help give you a way to encapsulate pieces of computation

 mechanism to achieve decomposition and abstraction


Functions help you give two really important aspects of computational thinking:
- Decomposition
- Abstraction.

February 22, 2016 6.0001 LECTURE 6 3


EXAMPLE -- PROJECTOR
 a projector is a black box
 don’t know how it works
 know the interface: input/output http://www.myprojectorlamps.com/blog/wp-content/
uploads/Dell-1610HD-Projector.jpg

 connect any electronics to it that can communicate


with that input
 black box somehow converts image from input source
to a wall, magnifying it
 ABSTRACTION IDEA: do not need to know how
projector works to use it
Abstraction: The idea that once you've built something, you don't need to know what's inside it as long as you know how it works.

If you give it appropriate inputs, it will behave in an appropriate way


February 22, 2016 6.0001 LECTURE 6 4
Decomposition - able to take different devices, have them synchronize, and in the end be able to achieve the same end goal

EXAMPLE -- PROJECTOR
 projecting large image for
Olympics decomposed into
separate tasks for separate
projectors
 each projector takes input
and produces separate output
 all projectors work together
to produce larger image
By Adenosine (Own work) [CC BY-SA 3.0
 DECOMPOSITION IDEA: (http://creativecommons.org/licenses/by-sa/3.0) or
different devices work GFDL (http://www.gnu.org/copyleft/fdl.html)], via
Wikimedia Commons
together to achieve an end
goal
February 22, 2016 6.0001 LECTURE 6 5
APPLY THESE IDEAS TO
PROGRAMMING
 DECOMPOSITION
• Break problem into different, self-contained, pieces
 ABSTRACTION
• Suppress details of method to compute something from
use of that computation

February 22, 2016 6.0001 LECTURE 6 6


CREATE STRUCTURE with
DECOMPOSITION
 in example, separate devices
 in programming, divide code into modules
• are self-contained
<-- Properties of Modules
• used to break up code
• intended to be reusable - structure code to be able to be reused in mutiple places

• keep code organized


• keep code coherent
 this lecture, achieve decomposition with functions
 in a few weeks, achieve decomposition with classes

February 22, 2016 6.0001 LECTURE 6 7


SUPPRESS DETAILS with
ABSTRACTION
 in example, no need to know how to build a projector
 in programming, think of a piece of code as a black box
• cannot see details
• do not need to see details
• do not want to see details
• hide tedious coding details
 achieve abstraction with function specifications or
docstrings

February 22, 2016 6.0001 LECTURE 6 8


DECOMPOSITION &
ABSTRACTION
 powerful together
 code can be used many times but only has to be
debugged once!

February 22, 2016 6.0001 LECTURE 6 9


February 22, 2016 6.0001 LECTURE 6 10
FUNCTIONS
 write reusable piece/chunks of code, called functions
 functions are not run in a program until they are
“called” or “invoked” in a program
 function characteristics:
• has a name
• has parameters (0 or more) Values inside function when you do a computation
• has a docstring (optional but recommended) tells you what the function does
• has a body sequence of command or instructions that we want to actually have happen

February 22, 2016 6.0001 LECTURE 6 11


HOW TO WRITE and
CALL/INVOKE A FUNCTION

def is_even( i ):

"""

Input: i, a positive int

Returns True if i is even, otherwise False

"""
expressions you want to evaluate when you're ready to use it. Notice the
print("hi”) indentation

return i%2 == 0

is_even(3)

February 22, 2016 6.0001 LECTURE 6 12


IN THE FUNCTION BODY
For example, if i've called is_even with the parameter 3, i now holds the value 3

So, now it will evaluate 3 remainder 2 and see whether it is equal to 0


def is_even( i ):

"""

Input: i, a positive int

Returns True if i is even, otherwise False

"""

print("hi”) Return tells you that you're ready to stop the computation.
return i%2 == 0 Whatever the following expression is, that is the value it
will give back to the person who asked for it.

In this case, it could have just been your shell, but it could
also be somebody else that's going to use it as part of
another computation

February 22, 2016 6.0001 LECTURE 6 13


February 22, 2016 6.0001 LECTURE 6 14
Function invocation (i.e. function calling) is really important.

VARIABLE SCOPE
 formal parameter gets bound to the value of
actual parameter when function is called
 new scope/frame/environment created when enter a function
 scope is mapping of names to objects

Global scope f scope


def f( x ):
f Some x
x = x + 1 3
code
print('in f(x): x =', x)

return x x 3
x = 3

z = f( x ) call to f, before z
body evaluated
February 22, 2016 6.0001 LECTURE 6 15
Anytime you do a invocation of a function, you create a new frame and bind the formal parameter of that function
to the values of the expressions passed in

VARIABLE SCOPE
 formal parameter gets bound to the value of
actual parameter when function is called
 new scope/frame/environment created when enter a function
 scope is mapping of names to objects

Global scope f scope


def f( x ):
f Some x
x = x + 1 4
code
print('in f(x): x =', x)

return x x 3
x = 3

z = f( x ) z
February 22, 2016 6.0001 LECTURE 6 16
VARIABLE SCOPE
 formal parameter gets bound to the value of
actual parameter when function is called
 new scope/frame/environment created when enter a function
 scope is mapping of names to objects

Global scope f scope


def f( x ):
f Some x
x = x + 1 4
code
print('in f(x): x =', x)

return x x 3
x = 3

z = f( x ) z
February 22, 2016 6.0001 LECTURE 6 17
VARIABLE SCOPE
 formal parameter gets bound to the value of
actual parameter when function is called
 new scope/frame/environment created when enter a function
 scope is mapping of names to objects

Global scope
def f( x ):
f Some
x = x + 1
code
print('in f(x): x =', x)

return x x 3
x = 3

z = f( x ) binding of returned value 4


to variable z z
February 22, 2016 6.0001 LECTURE 6 18
ONE WARNING IF NO
return STATEMENT
def is_even( i ):

"""
If no return statement, rather than returning i%2==0, Python will return
the value None because you did not give a return.
Input: i, a positive int
Represents the absence of value.
Does not return anything
Anytime you want a function to do something, you always want to have at
"""
least one return that gives a value back
i%2 == 0

 Python returns the value None, if no return given


 represents the absence of a value

February 22, 2016 6.0001 LECTURE 6 19


return vs. print
 return only has meaning  print can be used outside
inside a function functions
 only one return executed  can execute many print
inside a function statements inside a function
 code inside function but
after return statement not  code inside function can be
executed executed after a print
statement
 has a value associated
with it, given to function  has a value associated with
caller it, outputted to the console

February 22, 2016 6.0001 LECTURE 6 20


FUNCTIONS AS ARGUMENTS
 arguments can take on any type, even functions
Output:

inside func_a
def func_a(): takes no parameters None inside
func_b
print('inside func_a’) 7
inside func_c
def func_b(y): takes one parameter inside func_a
print('inside func_b’) None

return y
def func_c(z):
print('inside func_c’)
return z()
print(func_a())
print(5 + func_b(2))
in each case, evaluating body with respect to a
print(func_c(func_a)) frame

February 22, 2016 6.0001 LECTURE 6 21


Overall, you can look up values outside the scope, but
you can't change the value of these things outside of
the scope appropriately

SCOPE EXAMPLE
 inside a function, can access a variable defined outside
 inside a function, cannot modify a variable defined
trying to look up the
even though X
outside For g, first you call g with the value of x,
which is 5, which means 5 is going to be
local variable x and
= 5 in "global" won't succeed.
used in place of y
scope, it is def f(y): def g(y): def h(y):
redefined
inside the x = 1 print(x) print 5 x = x + 1
"local" scope
x += 1 print(x + 1)
print 6
print(x) x = 5
print 2 <- global
x = 5 environment h(x)
x = 5 g(x)call g = 5 print(x)
f(x) print(x)
print(x) print 5
Print statement will print
out the value 5 because it
sees the value of x defined in
the global scope

February 22, 2016 6.0001 LECTURE 6 22


SCOPE EXAMPLE
 inside a function, can access a variable defined outside
 inside a function, cannot modify a variable defined
outside
def f(y): def g(y): def h(y):
x = 1 print x x = x + 1
x += 1
print x x = 5
x = 5 h(2)
x = 5 g(2) print x
f(2) print x
print x in each case, x comes from global/
main program scope

February 22, 2016 6.0001 LECTURE 6 23


HARDER SCOPE EXAMPLE
IMPORTANT
and
TRICKY!

Python Tutor is your best friend to


help sort this out!
http://www.pythontutor.com/
February 22, 2016 6.0001 LECTURE 6 24
In this example, function defined inside another function.

Output: in g(x): x = 4

SCOPE DETAILS
def g(x): Global scope 1. g is bound to some code
2. h hasn't happened yet
def h(): 3. x is bound to 3
g Some
x = 'abc'
code
x = x + 1

print('in g(x): x =', x)


x 3
h() 1.

return x

z
x = 3 3.

z = g(x)

February 22, 2016 6.0001 LECTURE 6 25


SCOPE DETAILS
def g(x): 4. g creates a new scope,
Global scope g scope and in that scope, bind the
def h(): value of x, and that x is
coming from the formal
g Some x parameter for g,
x = 'abc'
3 5. the value is coming from
code the binding for x in the
x = x + 1
global scope, so x is bound
print('in g(x): x =', x) to 3
Some 5.Evaluate body of g
x 3 h 6. Only when you're inside
h() code of g you can use h
return x 7. Get current value of x,
which was 3, add 1 to it.

z
x = 3

z = g(x)

February 22, 2016 6.0001 LECTURE 6 26


SCOPE DETAILS
def g(x): Global scope g scope
8. Then, do the print
def h(): statement
g x 9. Which is why when it
x = 'abc' Some says g of x, x has got the
43
code value of 4
x = x + 1 10. Call h.
11. In h, evaluate body of
print('in g(x): x =', x) h.
x h Some
h() 3
code
return x

z
x = 3

z = g(x)

February 22, 2016 6.0001 LECTURE 6 27


12. the h() function invokes h, which creates a new
scope
13. This scope inhereits from g which inherits from
global scope
14. inside h, bind any formal paramters, but there aren't

SCOPE DETAILS any.


15. Therefore, evaluate body of h. Bind x to string "abc"
and return nothing

def g(x): Global scope g scope h scope


def h():
g Some x x
x = 'abc'
3
4 “abc”
code
x = x + 1

print('in g(x): x =', x)


x h Some
h() 3
code
return x

z
x = 3

z = g(x)

February 22, 2016 6.0001 LECTURE 6 28


16. Lastly, return value of x which is defined inside the scope
of g
17. That value gets returned as the value associated with Z,
and Z has the binding 4

SCOPE DETAILS
def g(x): Global scope g scope
def h():
g Some x
x = 'abc'
4
code
x = x + 1

print('in g(x): x =', x)


x h Some
h() 3
code
return x

None
z
x = 3

z = g(x)

February 22, 2016 6.0001 LECTURE 6 29


SCOPE DETAILS
def g(x): Global scope
def h():
g Some
x = 'abc'
code
x = x + 1

print('in g(x): x =', x)


x 3
h()

return x

z 4
x = 3

z = g(x)

February 22, 2016 6.0001 LECTURE 6 30


Python Methods

February 22, 2016 6.0001 LECTURE 6 31


KEYWORD ARGUMENTS AND
DEFAULT VALUES
 Simple function definition, if last argument is TRUE,
then print lastName, firstName; else firstName,
lastName
def printName(firstName, lastName, reverse):
if reverse:
print(lastName + ‘, ‘ + firstName)
else:
print(firstName, lastName)
You can have a function definition that you can change depending on how you want to invoke it.

February 22, 2016 6.0001 LECTURE 6 32


KEYWORD ARGUMENTS AND
DEFAULT VALUES
 Each of these invocations is equivalent
printName(‘Eric’, ‘Grimson’, False)

printName(‘Eric’, ‘Grimson’, reverse = False)

printName(‘Eric’, lastName = ‘Grimson’, reverse = False)

printName(lastName = ‘Grimson’, firstName = ‘Eric’,


reverse = False) <-- in this case, even if function expects FirstName and then LastName,
this still works

February 22, 2016 6.0001 LECTURE 6 33


KEYWORD ARGUMENTS AND
DEFAULT VALUES
 Can specify that some arguments have default values, so if no
value supplied, just use that value You can also give the default value in the beginning
as False
def printName(firstName, lastName, reverse = False):
if reverse:
print(lastName + ‘, ‘ + firstName)
else:
print(firstName, lastName)

printName(‘Eric’, ‘Grimson’)
printName(‘Eric’, ‘Grimson’, True)

February 22, 2016 6.0001 LECTURE 6 34


February 22, 2016 6.0001 LECTURE 6 35
Specification can be seen as a contract between implementor and the people who will use it.

It will say "here are the assumptions".

SPECIFICATIONS
 a contract between the implementer of a function and
the clients who will use it
• Assumptions: conditions that must be met by clients of
the function; typically constraints on values of parameters
• Guarantees: conditions that must be met by function,
providing it has been called in manner consistent with
assumptions
If assumptions are met, here are the guarantees.

February 22, 2016 6.0001 LECTURE 6 36


def is_even( i ):
"""
Input: i, a positive int <-- condition on the input

Returns True if i is even, otherwise False


Guarantee that it will return true if i is even, otherwise it will be False
"""
print "hi"
Not required to put DocString but it is best
practice. Helps understand code and where
return i%2 == 0 to use it

is_even(3)

February 22, 2016 6.0001 LECTURE 6 37


February 22, 2016 6.0001 LECTURE 6 38
Recursions help design solutions to problems by breaking things up into pieces you can use.

A programming technique where inside the function, it calls itself

WHAT IS RECURSION
 a way to design solutions to problems by divide-and-
conquer or decrease-and-conquer
 a programming technique where a function calls itself
 in programming, goal is to NOT have infinite recursion
• must have 1 or more base cases that are easy to solve
• must solve the same problem on some other input with
the goal of simplifying the larger problem input
In recusion, as long as you don't set up an infinite loop, then you're fine.

As long as you have 1 or more base case that is easy to solve, you can
reduce the solution into a simpler version of the same problem until
you get into a simple base case.

February 22, 2016 6.0001 LECTURE 6 39


So far, Iterative Algorithsms are basically Looping constructs

ITERATIVE ALGORITHMS SO FAR


 looping constructs (while and for loops) lead to
iterative algorithms
 can capture computation in a set of state variables
that update on each iteration through loop

February 22, 2016 6.0001 LECTURE 6 40


MULTIPLICATION –
ITERATIVE SOLUTION
 “multiply a * b” is equivalent to “add a to itself b times”
i.e. a + a + a + a + a <-- do it 'b' times
 capture state by
• an iteration number (i) starts at b
i  i-1 and stop when 0
• a current value of computation (result)
result  result + a
Output = 35
takes 2 parameters, a and b
def mult_iter(a, b):
result = 0
while b > 0:
result += a
b -= 1 keep doing it until b gets down to 0
return result
February 22, 2016 6.0001 LECTURE 6 41
MULTIPLICATION –
RECURSIVE SOLUTION
 recursive step a*b = a + a + a + a + … + a
adding a to itself b times
• think how to reduce
problem to a = a + a + a + a + … + a
simpler/smaller which is same as a to itself b-1 times
version of same
problem = a + a * (b-1)
now, we've taken a problem and reduced it into a simpler problem

 base case when b ==1 def mult(a, b):


• keep reducing if b == 1:
problem until reach a
simple case that can return a
be solved directly else:
• when b = 1, a*b = a return a + mult(a, b-1)
February 22, 2016 6.0001 LECTURE 6 42
FACTORIAL
n! = n*(n-1)*(n-2)*(n-3)* … * 1

 what n do we know the factorial of?


n=1  if n == 1:
return 1

 how to reduce problem? Rewrite in terms of


something simpler to reach base case
n*(n-1)!  else:
return n*factorial(n-1)

February 22, 2016 6.0001 LECTURE 6 43


how does the computer know
RECURSIVE FUNCTION SCOPE EXAMPLE def fact(n): which version of n to use?

1. When you define fact in global scope, you create a binding of if n == 1:


fact into some code
2. Call fact of 4 return 1
3. Fact creates a new scope where n is bound to 4
4. Is n == 1? no it's equal to 4
else:
5. Go to else clause: return n * fact of (n-1) return n*fact(n-1)
6. But you've got to first call fact. So this creates another new
frame, inside the formal parameter, where n is bound to 3
7. Is 3 = 1? no.
8. Then, return 3 * fact (n-1) (while calling fact, which is 2).
print(fact(4))
9. repeat... steps 4-8 until n ==1.
10. Then, returns 1. and returns back the numbers

Global scope fact scope fact scope fact scope fact scope
(call w/ n=4) (call w/ n=3) (call w/ n=2) (call w/ n=1)

fact Some n n n n
4 3 2 1
code

= 24 =6 =2

February 22, 2016 6.0001 LECTURE 6 44


SOME OBSERVATIONS

 each recursive call to a function creates its


own scope/environment
 bindings of variables in a scope is not
changed by recursive call
 flow of control passes back to previous
scope once function call returns value

February 22, 2016 6.0001 LECTURE 6 45


ITERATION vs. RECURSION
def factorial_iter(n): def factorial(n):
prod = 1 if n == 1:
for i in range(1,n+1): return 1
prod *= i else:
return prod return n*factorial(n-1)

 recursion may be simpler, more intuitive


 recursion may be efficient from programmer POV
 recursion may not be efficient from computer POV
In the end, both does the same thing, but you can decide which one you want to use

February 22, 2016 6.0001 LECTURE 6 46


February 22, 2016 6.0001 LECTURE 6 47
When you start trying to design code, you need to set up so that you know your recursive code will stop.

In iteration, you have a looping variable that will change so you know it will end. i.e. mult_iter decreases
by 1 each time which triggers the end clause

INDUCTIVE REASONING
 How do we know that our def mult_iter(a, b):
recursive code will work? result = 0
 mult_iter terminates while b > 0:
because b is initially positive, result += a
and decreases by 1 each time b -= 1
around loop; thus must
eventually become less than 1 return result

 mult called with b = 1 has no


recursive call and stops def mult(a, b):

 mult called with b > 1 makes if b == 1:


a recursive call with a smaller return a
version of b; must eventually
reach call with b = 1 else:
How do we know Recursive verison stops? Eventually, we know when b = 1.
In Recursive, we need to make sure we are changing the parameter so we return a + mult(a, b-1)
get down to the test case (i.e. if b ==1)

February 22, 2016 6.0001 LECTURE 6 48


MATHEMATICAL INDUCTION
 To prove a statement indexed on integers is true for all
values of n:
• Prove it is true when n is smallest value (e.g. n = 0 or n = 1)
• Then prove that if it is true for an arbitrary value of n, one
can show that it must be true for n+1

Mathematical Induction: If i want to prove a statement that is indexed on integers is true, for all values in a parameter n, we just have to
prove it's true when n has it's smallest value (n = 0 or n = 1).

- Then, prove that if it is true, on an arbitraty value of n, then we must show it's also true for n + 1

Then, you can deduce that it's true for all values that is n + 1

February 22, 2016 6.0001 LECTURE 6 49


EXAMPLE OF INDUCTION
 0 + 1 + 2 + 3 + … + n = (n(n+1))/2
 Proof
• If n = 0, then LHS is 0 and RHS is 0*1/2 = 0, so true
• Assume true for some k, then need to show that
◦ 0 + 1 + 2 + … + k + (k+1) = ((k+1)(k+2))/2
◦ LHS is k(k+1)/2 + (k+1) by assumption that property holds for
problem of size k
◦ This becomes, by algebra, ((k+1)(k+2))/2
• Hence expression holds for all n >= 0

February 22, 2016 6.0001 LECTURE 6 50


RELEVANCE TO CODE?
 Same logic applies
def mult(a, b):
if b == 1:
return a We need to prove that the base case is True

else:
return a + mult(a, b-1)
 Base case, we can show that mult must return correct answer
 For recursive case, we can assume that mult correctly returns an
answer for problems of size smaller than b, then by the addition step, it
must also return a correct answer for problem of size b
 Thus by induction, code correctly returns answer
February 22, 2016 6.0001 LECTURE 6 51
February 22, 2016 6.0001 LECTURE 6 52
TOWERS OF HANOI
 The story:
• 3 tall spikes
• Stack of 64 different sized discs – start on one spike
• Need to move stack to second spike (at which point
universe ends)
• Can only move one disc at a time, and a larger disc can
never cover up a small disc

By André Karwath aka Aka (Own work) [CC BY-SA 2.5 (http://creativecommons.org/licenses/by-sa/2.5)], via Wikimedia
Commons
February 22, 2016 6.0001 LECTURE 6 53
TOWERS OF HANOI
 Having seen a set of examples of different sized stacks,
how would you write a program to print out the right
set of moves?
 Think recursively!
• Solve a smaller problem move a stack of n-1 onto a spare disk

• Solve a basic problem


• Solve a smaller problem

February 22, 2016 6.0001 LECTURE 6 54


Print(Towers(4, 'P1', 'P2, 'P3))

def printMove(fr, to):


print('move from ' + str(fr) + ' to ' + str(to))

def Towers(n, fr, to, spare):


if n == 1: if stack of size 1, move it from From to To

printMove(fr, to)
else: 3, P1, P3, P2

Towers(n-1, fr, spare, to) move a smaller stack from the From to Spare slot
1, P1, P2, P3
Towers(1, fr, to, spare)
Towers(n-1, spare, to, fr) 3, P3, P2, P1
Note: you can have multiple recursive calls inside of a function body.

February 22, 2016 6.0001 LECTURE 6 55


February 22, 2016 6.0001 LECTURE 6 56
Having multiple base cases inside a problem

RECURSION WITH MULTIPLE


BASE CASES
 Fibonacci numbers
• Leonardo of Pisa (aka Fibonacci) modeled the following
challenge
◦ Newborn pair of rabbits (one female, one male) are put in a pen
◦ Rabbits mate at age of one month
◦ Rabbits have a one month gestation period
◦ Assume rabbits never die, that female always produces one new
pair (one male, one female) every month from its second month
on.
◦ How many female rabbits are there at the end of one year?

February 22, 2016 6.0001 LECTURE 6 57


Demo courtesy of Prof. Denny Freeman and Adam Hartz
Demo courtesy of Prof. Denny Freeman and Adam Hartz
Demo courtesy of Prof. Denny Freeman and Adam Hartz
Demo courtesy of Prof. Denny Freeman and Adam Hartz
Demo courtesy of Prof. Denny Freeman and Adam Hartz
Demo courtesy of Prof. Denny Freeman and Adam Hartz
Demo courtesy of Prof. Denny Freeman and Adam Hartz
February 22, 2016 6.0001 LECTURE 6 65
Demo courtesy of Prof. Denny Freeman and Adam Hartz
Demo courtesy of Prof. Denny Freeman and Adam Hartz
FIBONACCI
After one month (call it 0) – 1 female Month Females

After second month – still 1 female (now 0 1


pregnant) 1 1
2 2
After third month – two females, one pregnant,
3 3
one not
4 5
In general, females(n) = females(n-1) + 5 8
females(n-2) 6 13
◦ Every female alive at month n-2 will produce one
female in month n;
◦ These can be added those alive in month n-1 to
get total alive in month n

February 22, 2016 6.0001 LECTURE 6 68


FIBONACCI
 Base cases:
• Females(0) = 1 females at time 0

• Females(1) = 1 females at time 1

 Recursive case
• Females(n) = Females(n-1) + Females(n-2)
two invocations of this Females function.
One for n-1 and one for n-2

February 22, 2016 6.0001 LECTURE 6 69


def fib(x):
"""assumes x an int >= 0
returns Fibonacci of x""”
if x == 0 or x == 1: 2 base cases

return 1
else:
return fib(x-1) + fib(x-2)

February 22, 2016 6.0001 LECTURE 6 70


February 22, 2016 6.0001 LECTURE 6 71
RECURSION ON NON-
NUMERICS how to do recursive on strings?

 how to check if a string of characters is a palindrome, i.e.,


reads the same forwards and backwards
• “Able was I, ere I saw Elba” – attributed to Napoleon
• “Are we not drawn onward, we few, drawn onward to new era?” –
attributed to Anne Michaels

By Beinecke Library (Flickr: [General Napolean By Larth_Rasnal (Own work) [GFDL


Bonaparte]) [CC BY-SA 2.0 (http://www.gnu.org/copyleft/fdl.html) or CC BY 3.0
(http://creativecommons.org/licenses/by-sa/2.0)], (http://creativecommons.org/licenses/by/3.0)], via
via Wikimedia Commons Wikimedia Commons
February 22, 2016 6.0001 LECTURE 6 72
This can be done iteratively, but much easier to do it recursively

SOLVING RECURSIVELY?
 First, convert the string to just characters, by stripping
out punctuation, and converting upper case to lower
case
 Then
• Base case: a string of length 0 or 1 is a palindrome
• Recursive case:
◦ If first character matches last character, then is a palindrome if
middle section is a palindrome
If the string is empty, it's a palindrome.

If it's just length of 1, then it's a palindrome

Otherwise, how to tell if some string is a palindrome?


- check first and last element if it's a same.
- then, check everything in between.

Eventually, break it down and you'll eventually get to a string of 0 or a string of 1.


February 22, 2016 6.0001 LECTURE 6 73
EXAMPLE first, separate all the punctuation

‘Able was I, ere I saw Elba’  ‘ablewasiereisawleba’


isPalindrome(‘ablewasiereisawleba’)
is same as
• ‘a’ == ‘a’ and
isPalindrome(‘blewasiereisawleb’)
if first and last element are the same, then check if that is a palindrome

February 22, 2016 6.0001 LECTURE 6 74


def isPalindrome(s):
def toChars(s): Convert string into characters to convert everything to lowercase
s = s.lower()
ans = ''
for c in s: walk through each character in the string (string iteration)
if c in 'abcdefghijklmnopqrstuvwxyz':
ans = ans + c if character is a character, add it in
return ans
def isPal(s): if length 1 or less, it is a palindrome
if len(s) <= 1:
return True
else: otherwise, check 1st and last character of string, and check by slicing string everything but first char
return s[0] == s[-1] and isPal(s[1:-1])
return isPal(toChars(s))
Could you solve this iteratively? Yes, but more difficult. Recursively is much easier.

February 22, 2016 6.0001 LECTURE 6 75


DIVIDE AND CONQUER
 an example of a “divide and conquer” algorithm
 solve a hard problem by breaking it into a set of sub-
problems such that:
• sub-problems are easier to solve than the original (i.e. the problem is shorter)
• solutions of the sub-problems can be combined to solve
the original

February 22, 2016 6.0001 LECTURE 6 76


February 22, 2016 6.0001 LECTURE 6 77
with functions, we have the opportunity to create alot of functions. So far, we assumed all code stored in one file.

However, with so many functions, we need to think about how to However, this is cumbersome when we've
handle them got large collections of code.

MODULES AND FILES


 have assumed that all our code is stored in one file
 cumbersome for large collections of code, or for code
that should be used by many different other pieces of
programming
 a module is a .py file containing a collection Python
definitions and statements
Once you have a module, you can use it.

February 22, 2016 6.0001 LECTURE 6 78


EXAMPLE MODULE
 the file circle.py contains
pi = 3.14159
def area(radius):
return pi*(radius**2)
def circumference(radius):
return 2*pi*radius
 If you've saved this file somewhere, how can we use it?
- you can Import it either into another file, or into the
shell itself.

February 22, 2016 6.0001 LECTURE 6 79


EXAMPLE MODULE
 then we can import and use this module:
import circle by using the Import function, it goes and finds that file, and it reads all the statements in that
file into the shell.
pi = 3
Inside the shell, you can redefine the pi b/c you're walking inside the shell.
print(pi)
print(circle.pi) you can also print out the value of Pi that was defined in the module Circle

print(circle.area(3)) Inside circle module, get the function called area and call it on argument 3

print(circle.circumference(3))
 results in the following being printed:
3
3.14159
28.27431
18.849539999999998

February 22, 2016 6.0001 LECTURE 6 80


OTHER IMPORTING
 if we don’t want to refer to functions and variables by their
module, and the names don’t collide with other bindings,
then we can use:
from circle import * from circle import everything (which is the *)

print(pi)
print(area(3))
 this has the effect of creating bindings within the current
scope for all objects defined within circle
 statements within a module are executed only the first
time a module is imported

February 22, 2016 6.0001 LECTURE 6 81


FILES
 need a way to save our work for later use
 every operating system has its own way of handling
files; Python provides an operating-system
independent means to access files, using a file handle
nameHandle = open(‘kids’, ‘w’)
 creates a file named kids and returns file handle
which we can name and thus reference. The w
indicates that the file is to opened for writing into.
open will open the file with the name kids and the 'w' means open for writing

February 22, 2016 6.0001 LECTURE 6 82


FILES: example
nameHandle = open(‘kids’, ‘w’)
for i in range(2):
name = input(‘Enter name: ‘)
nameHandle.write(name + ‘\’)
nameHandle.close()
what we're doing now is writing directly into the file "kids"

February 22, 2016 6.0001 LECTURE 6 83


FILES: example
nameHandle = open(‘kids’, ‘r’) 'r' means "read" a file

for line in nameHandle:


print(line)
nameHandle.close()

February 22, 2016 6.0001 LECTURE 6 84

You might also like