* Decorator is a Higher Order Function.
* Higher Order Function means a function that returns a function or take a function as an argument(or both).
* 懶人包:如果要對每個function做benchmarking(測時間)或是logging之類的統一動作,可以把code寫在裝飾器裡面,這樣呼叫function的同時就會先執行裝飾器,再執行function
### 1. Define a normal function:
```python
def original_func():
print("The original function starts...")
print("This function will return 2")
print("The original function ends...")
return 2
```
### 2. Defin a decorator:
```python
def decorator_func(function):
def square():
print("The decorated function starts...")
print("This function will return the square of the number")
print("The decorated function ends...")
return function() ** 2
return square
```
### 3. Use the decorator:
```python
result = decorator_func(original_func)()
print(result)
```
> The decorated function starts...
This function will return the square of the number
The decorated function ends...
The original function starts...
This function will return 2
The original function ends...
4
### 4. Special syntax:
A easier way to invoke decorator_func(original_func).
By adding @decorator, we can just simply use the original function name to invoke a function instead of typing more words.
```python
def decorator_func(function):
def square():
print("The decorated function starts...")
print("This function will return the square of the number")
print("The decorated function ends...")
return function() ** 2
return square
@decorator_func
def original_func():
print("The original function starts...")
print("This function will return 2")
print("The original function ends...")
return 2
result = original_func()
print(result)
```
### 5. Application: Features Analysis
1. Create some fake data
```python=
import pandas as pd
d = {
"feature_1": [1, 2, 3, 4, 5],
"feature_2": [16, 28, 33, 45, 65]
}
fake_data = pd.DataFrame(d)
```
result:
```
feature_1 feature_2
0 1 16
1 2 28
2 3 33
3 4 45
4 5 65
```
2. Create features
```python
# feature_3: feature_1 + feature_2
def generate_feature_3(data: pd.DataFrame) -> pd.DataFrame:
data["feature_3"] = data["feature_1"] + data["feature_2"]
return data
# feature_4: feature_1 / feature_2
def generate_feature_4(data: pd.DataFrame) -> pd.DataFrame:
data["feature_4"] = data["feature_1"] / data["feature_2"]
return data
features = fake_data.copy()
for generate_function in [generate_feature_3, generate_feature_4]:
generate_function(features)
```
result:
```
feature_1 feature_2 feature_3 feature_4
0 1 16 17 0.062500
1 2 28 30 0.071429
2 3 33 36 0.090909
3 4 45 49 0.088889
4 5 65 70 0.076923
```
If we want to increase/delete any feature generation function, it will become less efficient to mantain the code.
So, we could use "Decorator" to help.
```python
# revised with decorator
register_list = []
def register(function):
register_list.append(function)
print(f"REGISTER: {function}")
return function
@ register
def generate_feature_3(data: pd.DataFrame) -> pd.DataFrame:
data["feature_3"] = data["feature_1"] + data["feature_2"]
return data
@register
def generate_feature_4(data: pd.DataFrame) -> pd.DataFrame:
data["feature_4"] = data["feature_1"] / data["feature_2"]
return data
features = fake_data.copy()
for generate_function in register_list:
generate_function(features)
print(features)
```