COMP280:Introduction to Software Development, Week 9, Lecture 27 Bernhard Pfahringer
How about a general solution to caching? def memo(f): memo = {} def helper(x): if x not in memo: memo[x] = f(x) return memo[x] return helper @memo def fib(n): return n if n < 2 else fib(n-1) + fib(n-2)
An example of the Decorator pattern @memo def fib(n): … Is equivalent to the following: fib = memo(fib) @memo can be used/wrapped around any function More on “Patterns” later
What else is wrong with fib(n) ? >>> fib( -10 ) -10 ??? >>> fib( 10.2 ) 72.79999999999993
Checking input validity def fib(n): assert type(n) is int assert n >= 0 return n if n < 2 else fib(n-1) + fib(n-2) if type(n) is not int: raise TypeError( "fib: n must be an int: ” + str(n)) if n < 0: raise ValueError( "fib: must be non-negative: %d” % n) More on “defensive programming” later
What is still wrong with fib(n) ? >>> help( fib ) ??? def fib(n): """Compute Fibonacci numbers""" return n if n < 2 else fib(n-1) + fib(n-2) >>> help(fib) fib(n) Compute Fibonacci numbers More on ”documenting code” later
What else is missing: Testing def fib(n): """Compute Fibonacci numbers >>> fib(0) 0 >>> fib(30) 832040 """ return n if n < 2 else fib(n-1) + fib(n-2) if __name__ == '__main__': import doctest doctest.testmod()
Putting it all together def fib(n): """Compute Fibonacci numbers >>> fib(0) 0 >>> fib(30) 832042 """ if type(n) is not int: raise TypeError( "fib: n must be an int: {}”.format(n)) if n < 0: raise ValueError( "fib: n must be non-negative: {}”.format(n)) if n < 2: return n else: a, b = 0, 1 for i in range(n-1): a, b = b, a+b return b
Design Patterns 1994 book by GoF “Gang of Four” Gamma, Helm, Johnson, Vlissides Template solution for common problem Make up for a deficiency/shortcoming of the language lack of library Also help documenting/understanding systems Generally: Patterns use classes and instances to explicitly represent actions
Groups of patterns Creational, e.g. Structural, e.g. Behavioural, e.g. Prototype Abstract Factory Builder Structural, e.g. Adapter Decorator Proxy Behavioural, e.g. Iterator Command [Concurrency] [Architecture]
Prototype [ plus shallow and deep copying ] Creating an instance using another as a template In Java or C/C++: copy-constructor Python: only one __init__ (more or less) but copy(), copy.deepcopy(), __copy__, __deepcopy__ a = [ [ 0 ] ] b = a.copy() a[0][0] = 1 b ? b[0] = 2 a ? a = [ [ 0 ], 1] a[1] = a[0] a ? a[0][0] = 1 b = copy.deepcopy(a) b[0][0] = 2 b ?