Advanced Interactions

Lambda Functions

(anonymous functions) from Lisp & functional programming

In [ ]:
tmp = lambda x: x**2
print(type(tmp))
In [ ]:
tmp(2)
In [ ]:
# forget about creating a new function name...just do it!
(lambda x,y: x**2+y)(2,4.5)
In [ ]:
## create a list of lambda functions
lamfun = [lambda x: x**2, lambda x: x**3, \
           lambda y: math.sqrt(y) if y >= 0 else "Really? I mean really? %f" % y]
In [ ]:
for l in lamfun: print(l(-1.3))
lambda functions are meant to be short, one liners. If you need more complex functions, probably better just to name them
In [ ]:
# %load airline.py
airports = {"DCA": "Washington, D.C.", "IAD": "Dulles", "LHR": "London-Heathrow", \
            "SVO": "Moscow", "CDA": "Chicago-Midway", "SBA": "Santa Barbara", "LAX": "Los Angeles",\
            "JFK": "New York City", "MIA": "Miami", "AUM": "Austin, Minnesota"}
            
# airline, number, heading to, gate, time (decimal hours) 
flights = [("Southwest",145,"DCA",1,6.00),("United",31,"IAD",1,7.1),("United",302,"LHR",5,6.5),\
           ("Aeroflot",34,"SVO",5,9.00),("Southwest",146,"CDA",1,9.60), ("United",46,"LAX",5,6.5),\
           ("Southwest",23,"SBA",6,12.5),("United",2,"LAX",10,12.5),("Southwest",59,"LAX",11,14.5),\
           ("American", 1,"JFK",12,11.3),("USAirways", 8,"MIA",20,13.1),("United",2032,"MIA",21,15.1),\
           ("SpamAir",1,"AUM",42,14.4)]
In [ ]:
help(list.sort)
In [ ]:
flights.sort(key=lambda x: x[4]) ; 
print(flights)
In [ ]:
import pprint
pprint.pprint(flights)

Multiple column sorting

operator.itemgetter(item[, args...])

Return a callable object that fetches item from its operand using the operand’s __getitem__() method. If multiple items are specified, returns a tuple of lookup values.

http://docs.python.org/library/operator.html#module-operator

In [ ]:
import operator
flights.sort(key=operator.itemgetter(4,1,0))
flights

Filter is a certain way to do list comprehension

filter(function, sequence) returns a sequence consisting of those items from the sequence for which function(item) is true

In [ ]:
mylist=[num for num in range(101) if (num & 2) and (num & 1) and (num % 11 != 0.0)]
print(mylist)
In [ ]:
def f(num): return (num & 2) and (num & 1) and (num % 11 != 0.0)

mylist = list(filter(f,range(101)))
print(mylist)
In [ ]:
mylist = list(map(lambda num: (num & 2) and (num & 1) and (num % 11 != 0.0),range(101)))
print(mylist)

if the input is a string, so is the output...

In [ ]:
## also works on strings...try it with lambdas!
import string
a="Charlie Brown said \"[email protected][email protected][email protected]!\""
"".join([c for c in a if c in string.ascii_letters])
In [ ]:
", ".join([str(num) for num in range(101) if (num & 2) and \
           (num & 1) and (num % 11 != 0.0)])

[back]

Map is just another way to do list comprehension

In [ ]:
def timesthree(x): return x*3
list(map(timesthree,"spam"))
In [ ]:
list(map(lambda x: x**3, range(1,10)))

Reduce returns one value

reduce(function, sequence) returns a single value constructed by calling the binary function on the first two items of the sequence, then on the result and the next item, and so on

In [ ]:
from functools import reduce
# sum from 1 to 10
reduce(lambda x,y: x + y, range(1,11))   
%timeit reduce(lambda x,y: x + y, range(1,11))
In [ ]:
reduce(lambda x,y: x + y, range(11,1,-1)) 
In [ ]:
list(range(11,1,-1))
In [ ]:
a = ["a","b"]
In [ ]:
reduce?
In [ ]:
# sum() is a built in function...it’s bound to be faster
%timeit sum(range(1,11))

zip()

built in function to pairwise concatenate items in iterables into a list of tuples

In [ ]:
list(zip(["I","you","them"],["=spam","=eggs","=dark knights"]))
In [ ]:
list(zip(["I","you","them"],["=spam","=eggs","=dark knights"],["!","?","#"]))
In [ ]:
a = list(zip(["I","you","them"],["=spam","=eggs","=dark knights"],["!","?","hello","blah"]))
In [ ]:
a[0][1] = "=eggs"
In [ ]:
questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for a,q in zip(questions, answers):
    print('What is your %s?  It is %s' % (q,a))

not to be confused with zipfile module which exposes file compression

try, except, finally

  • Billy: Let's keep going with "Airplanes", for \$200.
  • Bobby Wheat: "Airplanes" for \$200: "And what is the Deal With the Black Box?"
  • [ Tommy buzzes in ] Tommy!
  • Tommy: It's the only thing that survives the crash - why don't they build the whole plane out of the Black Box!

http://snltranscripts.jt.org/91/91rstandup.phtml

http://www.nbc.com/saturday-night-live/video/standup-and-win/2868123

Wrap volatile code in try/except/finally

instead of ...

In [ ]:
tmp = input("Enter a number and I'll square it: ") ; print(float(tmp)**2)

do this...

In [ ]:
def f():
    try:
       tmp = input("Enter a number and I'll square it: ")
       print(float(tmp)**2)
    except:
       print("dude. I asked you for a number and %s is not a number." % tmp)
    finally:
       print("thanks for playing!")
In [ ]:
f()

Wrap volatile code in try/except/finally

try:
   # volatile stuff here
   tmp = raw_input("Enter a number “ + \
                   and I'll square it: ")
   print(float(tmp)**2)
except:
   # upon error, jump here inside except and execute that code
   print("dude. I asked you for a number and " + \
    "%s is not a number." % tmp)
finally:
   # regardless of whether you hit an error, execute everything inside the finally block
   print("thanks for playing!")
In [ ]:
try:
  print("eat at" % joes)
finally:
  print("bye.") 
  • errors in Python generate what are called “exceptions”
  • exceptions can be handled differently depending on what kind of exception they are (we’ll see more of that later)
  • except “catches” these exceptions
  • you do not have to catch exceptions (try/finally) is allowed. Finally block is executed no matter what!

exec & eval

exec is a statement which executes strings as if they were Python code

In [ ]:
a = "print('checkit')"
print(a)
In [ ]:
exec(a)
In [ ]:
a = "x = 4.56" 
In [ ]:
exec(a)
In [ ]:
print(x)
In [ ]:
exec("del x")
In [ ]:
print(x)
  • dynamically create Python code (!)
  • execute that code w/ implications for current namespace
In [ ]:
import math
while True:
    bi = input("what built in function would you like me to coopt? ")
    if bi in ('?',"",'end'):
        break
    nn = input("what new name would you like to give it? ")
    exec("%s = %s" % (nn,bi))
In [ ]:
jsin(math.pi/2)

eval is an expression which evaluates strings as Python expressions

In [ ]:
x = eval('5')  ; print(x)             # x <- 5
x = eval('%d + 6' % x)  ; print(x)   # x <- 11
x = eval('abs(%d)' % -100) ; print(x) # x <- 100
In [ ]:
eval('if 1: x = 4') # INVALID; if is a statement, not an expression.

Breakout

Write a code which generates python code that approximates the function: $$x^2 + x$$

hints:

  • randomly generate lambda functions using a restricted vocabulary: voc =["x","x"," ","+","-","*","/","1","2","3"]

  • evaluate these lambda functions at a fix number of x values and save the difference between those answers and x**2 + x

  • catch errors!

  • start with a file like:

import random
import numpy

voc =["x","x"," ","+","-","*","/","1","2","3"]

nfunc       = 1000000
maxchars = 10  # max how many characters to gen
eval_places = numpy.arange(-3,3,0.4)
sin_val     = eval_places**2 + eval_places
tries       = []
for loop...
In [ ]: