###### tags: Python # Funtional Programming function / data seperation ## 4 Pillars of Functional Programming ### 1. Pure Functions giving same input always gets the same output without having any side effect(interact with outside world) function藉由產生新的object方式不去改變原始的data ``` def multiply_by2(li): new_list = [] for item in li: new_list.append(item*2) return new_list ``` #### Example for pure function my_list = [1,2,3] your_list = [10,20,30] - Map ``` map(function, data) def multiply_by2(item): return item*2 print(list(map(multiply_by2, my_list)) ``` - Filter ``` def only_odd(item): return item % 2 != 0 print(list(filter(only_odd, my_list)) ``` - Zip - combine lists into tuple `print(list(zip(my_list, your_list)))` - Reduce ``` from functools import reduce def accumulator(acc, item): return acc + item print(reduce(accumulator, my_list, 0)) ``` - Lambda - one time anonymous fuction using the fuction only once `lambda param: action(param)` lambda item: item*2 ### 2. Comprehension comprehension will make codes less readable, make sure to describe it while using comprehension - List `my_list = [param for param in iterable]` ``` my_list = [] for char in 'hello': my_list.append(char) ``` ``` my_list = [char for char in 'hello'] my_list2 = [num**2 for num in range(0,100)] my_list3 = [num**2 for num in range(0,100) if num % 2 == 0] ``` - Set ``` my_set = {char for char in 'hello'} my_set2 = {num**2 for num in range(0,100)} my_set3 = {num**2 for num in range(0,100) if num % 2 == 0} ``` - Dictionary `my_dict = {key:value** for key,value in}` ``` simple_dic = { 'a' : 1, 'b' : 2 } ``` `my_dict = {k:v**2 for k,v in simple_dict.items() if v%2==0}` `my_dict = {num:num*2 for num in [1,2,3]}` ### 3. Decorators Higher Order Function(HOC) Parameters of function include function @classmethod @staticmethod ``` def my_decorator(func): def wrap_func(*args, **kwargs): print('*****') func(*args, **kwargs) print('*****') return wrap_func @my_decorator def hello(greeting, emoji=':('): print(greeting, emoji) hello('hiiii') ``` ``` def my_decorator(func): def wrap_func(): print('*****') func() print('*****') return wrap_func my_decorator(hello()) ``` output: ``` ***** hello ***** ``` - Example ``` from time import time def performance(fn): def wrapper(*args, **kwargs): t1 = time() result = fn(*args, **kwargs) t2 = time() print(f'took {t2-t1} s') return result return wrapper @performance def long_time(): for i in range(1000000): i*5 long_time() ``` output: ``` took 1.9 s ``` ### 4. Generator 節省記憶體空間&更有效率 一次跑一個值出來取代原本記憶體上同位置的值 range is a generator generator is subset of iterable ``` def generator_func(num): for i in range(num): yield i*2 g = generator_func(100) print(g) --> output: memory position print(next(g)) --> output: 0 ``` ``` def sepcial_for(iterable): iterator = iter(iterable) while True: try: print(iterator) next(iterator) except StopIteration: break special_for([1,2,3]) ``` ``` class MyGen(): current = 0 def __init__(self, first, last): self.first = first self.last = last def __iter__(self): return self def __next__(self): if MyGen.current < self.last: num = MyGen.current MyGen.current +=1 return num raise StopIteration gen = MyGen(0,100) for i in gen: print(i) ``` ### Error Handling ``` while True: try: age = input('what is your age? ') 10/age raise ValueErroe('hey cut it out') except ValueError: print('please enter a number') continue except ZeroDivisionError: print('please enter age higher than 0') break else: print('thank you!') finally: print('ok, i am finally done') print('can you hear me?') ``` ``` def sum(num1, num2): try: return num1 + num2 except TypeError as err: print(f'please enter numbers {err}') ``` ``` def sum(num1, num2): try: return num1/num2 except (TypeError, ZeroDivisionError) as err: print(err) ```