Discovered by Virahanka in India, 600800 AD, later rediscovered in Western mathematics and commonly known as Fibonacci numbers.
How many poetic meters exist for a total duration?
S = short syllable, L = long syllable
Duration  Meters  Total 

1  S  1 
2  SS, L  2 
3  SSS, SL, LS  3 
4  SSSS, SSL, SLS, LSS, LL  5 
5  SSSSS, SSSL, SSLS, SLSS, SLL, LLS, LSL, LSSS  8 
The Socalled Fibonacci Numbers in Ancient and Medieval India
How many pairs of rabbits can be bred after N months?
Attribution: Fschwarzentruber, Wikipedia
VF 0 1 1 2 3 5 8 13 21 34 55 …
N 0 1 2 3 4 5 6 7 8 9 10 …
def vf_number(n):
"""Compute the nth VirahankaFibonacci number, for N >= 1.
>>> vf_number(2)
1
>>> vf_number(6)
8
"""
prev = 0 # First Fibonacci number
curr = 1 # Second Fibonacci number
k = 1
while k < n:
(prev, curr) = (curr, prev + curr)
k += 1
return curr
The Golden spiral can be approximated by VirahankaFibonacci numbers.
The Golden spiral is found everywhere in nature...
def square(x):
"""Returns the square of X."""
return x * x
Aspect  Example 

A function's domain is the set of all inputs it might possibly take as arguments.  x is a number

A function's range is the set of output values it might possibly return.  square returns a nonnegative real number

A pure function's behavior is the relationship it creates between input and output.  square returns the square of x

Give each function exactly one job, but make it apply to many related situations.
round(1.23) # 1
round(1.23, 0) # 1
round(1.23, 1) # 1.2
round(1.23, 5) # 1.23
Don't Repeat Yourself (DRY): Implement a process just once, execute it many times.
Geometric shapes have similar area formulas.
Shape  

Area  $$\colorbox{#f8e9eb}{$1$} * r^2$$  $$\colorbox{#f8e9eb}{$\pi$} * r^2$$  $$\colorbox{#f8e9eb}{$\dfrac{3\sqrt{3}}{2}$} * r^2$$ 
from math import pi, sqrt
def area_square(r):
return r * r
def area_circle(r):
return r * r * pi
def area_hexagon(r):
return r * r * (3 * sqrt(3) / 2)
How can we generalize the common structure?
from math import pi, sqrt
def area(r, shape_constant):
"""Return the area of a shape from length measurement R."""
if r < 0:
return 0
return r * r * shape_constant
def area_square(r):
return area(r, 1)
def area_circle(r):
return area(r, pi)
def area_hexagon(r):
return area(r, 3 * sqrt(3) / 2)
A function that either:
All other functions are considered firstorder functions.
$$\sum\limits_{k=1}^5 \colorbox{#f8e9eb}{$k$} = 1 + 2 + 3 + 4 + 5 = 15$$ $$\sum\limits_{k=1}^5 \colorbox{#f8e9eb}{$k^3$} = 1^3 + 2^3 + 3^3 + 4^3 + 5^3 = 225$$ $$\sum\limits_{k=1}^5 \colorbox{#f8e9eb}{$\dfrac{8}{(4k  3)\cdot(4k  1)}$} = \dfrac{8}{3} + \dfrac{8}{35} + \dfrac{8}{99} + \dfrac{8}{195} + \dfrac{8}{323} = 3.04$$
The common structure among functions may be a computational process, not just a number.
def cube(k):
return k ** 3
def summation(n, term):
"""Sum the first N terms of a sequence.
>>> summation(5, cube)
225
"""
total = 0
k = 1
while k <= n:
total = total + term(k)
k = k + 1
return total
Functions defined within other function bodies are bound to names in a local frame.
def make_adder(n):
"""Return a function that takes one argument k
and returns k + n.
>>> add_three = make_adder(3)
>>> add_three(4)
7
"""
def adder(k):
return k + n
return adder
A lambda expression is a simple function definition that evaluates to a function.
The syntax:
lambda <parameters>: <expression>
A function that takes in parameters
and returns the result of expression
.
A lambda version of the square
function:
square = lambda x: x * x
A function that takes in parameter x
and returns the result of x * x
.
A lambda expression does not contain return statements or any statements at all.
Incorrect:
square = lambda x: return x * x
Correct:
square = lambda x: x * x

vs 


Both create a function with the same domain, range, and behavior.  
Both bind that function to the name square.  
Only the def statement gives the function an intrinsic name, which shows up in
environment diagrams but doesn't affect execution (unless the function is printed).

It's convenient to use a lambda expression when you are passing in a simple function as an argument to another function.
Instead of...
def cube(k):
return k ** 3
summation(5, cube)
We can use a lambda:
summation(5, lambda k: k ** 3)
A conditional expression has the form:
<consequent> if <predicate> else <alternative>
Evaluation rule:
This is invalid syntax:
lambda x: if x > 0: x else: 0
Conditional expressions to the rescue!
lambda x: x if x > 0 else 0