Class Notes: Functions Redux


  1. Variable length args (*args)
  2. Default args
    1. Default args example
    2. Do not use mutable default args
    3. One workaround for mutable default args
  3. Functions as parameters
  4. Lambda functions
  5. Keyword args (**kwargs)
  6. Functions inside functions
  7. Closures + Non-local variables
  8. Non-local variables fail on setting
  9. Functions that return functions
  10. Function decorators


  1. Variable length args (*args)

  2. def longestWord(*args): if (len(args) == 0): return None result = args[0] for word in args: if (len(word) > len(result)): result = word return result print(longestWord("this", "is", "really", "nice")) # really mywords = ["this", "is", "really", "nice"] print(longestWord(mywords)) # ['this', 'is', 'really', 'nice'] print(longestWord(*mywords)) # really

  3. Default args

    1. Default args example
    2. def f(x, y=10): return (x,y) print(f(5)) # (5, 10) print(f(5,6)) # (5, 6)

    3. Do not use mutable default args
    4. def f(x, L=[ ]): L.append(x) return L print(f(1)) print(f(2)) # why is this [1, 2]?

    5. One workaround for mutable default args
    6. def f(x, L=None): if (L == None): L = [ ] L.append(x) return L print(f(1)) print(f(2)) # [2] (that's better)

  4. Functions as parameters

  5. def derivative(f, x): h = 10**-8 return (f(x+h) - f(x))/h def f(x): return 4*x + 3 print(derivative(f, 2)) # about 4 def g(x): return 4*x**2 + 3 print(derivative(g, 2)) # about 16 (8*x at x==2)

  6. Lambda functions

  7. print(derivative(lambda x:3*x**5 + 2, 2)) # about 240, 15*x**4 at x==2 myF = lambda x: 10*x + 42 print(myF(5)) # 92 print(derivative(myF, 5)) # about 10

  8. Keyword args (**kwargs)

  9. def f(x=1, y=2): return (x,y) print(f()) # (1, 2) print(f(3)) # (3, 2) print(f(y=3)) # (1, 3) [here is where we use a keyword arg] def f(x, **kwargs): return (x, kwargs) print(f(1)) # (1, { }) print(f(2, y=3, z=4)) # (2, {'z': 4, 'y': 3})

  10. Functions inside functions

  11. def f(L): def squared(x): return x**2 return [squared(x) for x in L] print(f(range(5))) try: print(squared(5)) except: print("squared is not defined outside f")

  12. Closures + Non-local variables

  13. def f(L): myMap = dict() def squared(x): result = x**2 myMap[x] = result return result squaredList = [squared(x) for x in L] return myMap print(f(range(5)))

  14. Non-local variables fail on setting (use nonlocal)

  15. def brokenF(L): lastX = 0 def squared(x): result = x**2 lastX = x return result squaredList = [squared(x) for x in L] return lastX print(brokenF(range(5))) def fixedF(L): lastX = 0 def squared(x): nonlocal lastX result = x**2 lastX = x return result squaredList = [squared(x) for x in L] return lastX print(fixedF(range(5)))

  16. Functions that return functions

  17. def derivativeFn(f): def g(x): h = 10**-5 return (f(x+h) - f(x))/h return g def f(x): return 5*x**3 + 10 fprime1 = derivativeFn(f) fprime2 = derivativeFn(fprime1) print(f(3)) # 145, 5*x**3 + 10 evaluated at x == 3 print(fprime1(3)) # about 135, 15*x**2 evaluated at x == 3 print(fprime2(3)) # about 90, 30*x evaluated at x == 3

  18. Function decorators

  19. @derivativeFn def h(x): return 5*x**3 + 10 print(h(3)) # 135, matches fprime1 from above.