###### 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)
```