# fn is a perfectly respectable function fn = lambda x,y: x*y type(fn) fn(2,4) def pure_fn(x,y): z = x + y return z * 2 def impure_fn(l): print(l) l[0] = l[0] -1 # and we don't even return anything, how rude mylist = [2] impure_fn(mylist) print(mylist) # Functions are values and so... a = pure_fn a(5,6) l = [5,3,5,6,1,2,9,3] double_l = map(lambda x: x * 2, l) double_l # We have to cast result to # list type with list() list(double_l) l l = [5,3,5,6,1,2,9,3] list(filter(lambda x: x % 2 == 0, l)) help(functools.reduce) def reduce_(fn, seq, seed=None): """ fn is a function that takes two arguments and returns one result. The initial seed is optional. If there's one thing left in the sequence, use it as an arg and the seed as the other. Otherwise, recursively eat up the sequence. """ if len(seq) == 1 and seed is None: return seq[0] elif len(seq) == 0: return seed return fn(seq[0], reduce_(fn, seq[1:], seed)) def tish(s1, s2): return s1 + " TISH " + s2 # 2! 4! 6! 8! EVERYONE INTERCALATE! reduce_(tish, ["BOOM", "BOOM", "BOOM", "BOOM"]) reduce_(lambda x, y: x+y, [1, 2, 3, 4, 5], 10) fruits = ["apple", "banana", "avocado"] # cf Haskell # import Data.Char # [map toUpper fruit | fruit <- ["apple", "banana", "pear"], head fruit == 'a'] [fruit.upper() for fruit in fruits if fruit.startswith("a")] def adder_factory(i): k = 30 def adder(j): # i, j and k are "open" variables in adder's scope return i + j + k return adder add5 = adder_factory(5) adder_factory = None # Mysteriously, i j and k must still be around somehow. Those bindings were closed. add5(10) def print_args(fn): """ We're going to make a new function called "wrapped". wrapped will get called whenever another function is decorated with print_args. """ def wrapped(*args): print ("Called", fn.__name__, "with:", args,) result = fn(*args) print ("resulting in:", result) return result return wrapped @print_args def add_nums(i, j): return i + j add_nums(4,5) def add_nums2(i, j): return i + j add_nums2 = print_args(add_nums2) add_nums2(4,5) import itertools import functools import operator list(itertools.accumulate( [1,2,3,4], operator.add)) #help(itertools.accumulate) import functools import operator functools.reduce(operator.mul, [1,2,3,4]) l = [3, 2, 5, 1] sorted(l) l l.sort() l l.sort() print (list(reversed(l))) # reversed returns an iterator print (l) l.reverse() print (l) list(map((lambda tup:tup[0]*tup[1]), [(2,3),(4,4)])) # This example and subsequent para stolen from Brian Chikilian def create_multipliers(): return [lambda x : i * x for i in range(5)] for multiplier in create_multipliers(): print (multiplier(2)) def create_multipliers(): return [lambda x, i=i : i * x for i in range(5)] # note the i=i in the lambda parameter for multiplier in create_multipliers(): print (multiplier(2)) import functools def _compose_helper(fn1, fn2): # Make a new function that takes the args, # calls fn1 with them # and then passes the result to fn2 def _fn(*args): return fn1(fn2(*args)) return _fn def compose(*fns): # Glom all the functions in fns together # by repeatedly applying _compose_helper return functools.reduce(_compose_helper, fns) # Side note on readability: if we were steeped in FPness, we might just write: compose2 = lambda *fns: functools.reduce(lambda f1, f2: lambda *args: f1(f2(*args)), fns) # Resist that urge if you want to have friends. def centre_wide(s): return s.center(80) def upper(s): return s.upper() def word_count(s): return s + "(%d)" % len(s.split()) def no_pants(s): return s.replace("trousers", "****") lines = ["In the beginning", "there was stuff like trousers", "but we hated wearing trousers because trousers suck"] star_wars = compose2(upper, word_count, centre_wide, no_pants, ) print("\n".join([star_wars(s) for s in lines]))