decorators doc
This commit is contained in:
182
Docs/Basic/08-decorators.md
Normal file
182
Docs/Basic/08-decorators.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# 08 – Decorators in Python
|
||||
|
||||
This document explains **decorators**, how they work, and how they are used to extend function behavior without modifying the original function code.
|
||||
|
||||
---
|
||||
|
||||
## 1. What Is a Decorator?
|
||||
|
||||
A **decorator** is a function that:
|
||||
|
||||
* Takes another function as input
|
||||
* Adds extra behavior
|
||||
* Returns a new function
|
||||
|
||||
Decorators are commonly used for:
|
||||
|
||||
* Input validation
|
||||
* Logging
|
||||
* Authentication
|
||||
* Performance measurement
|
||||
* Access control
|
||||
|
||||
---
|
||||
|
||||
## 2. Basic Decorator Structure
|
||||
|
||||
A decorator has three layers:
|
||||
|
||||
1. The decorator function
|
||||
2. The wrapper function
|
||||
3. The original function
|
||||
|
||||
### General Pattern
|
||||
|
||||
```python
|
||||
def decorator(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
# extra behavior
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Example: Input Validation Decorator
|
||||
|
||||
### Code
|
||||
|
||||
```python
|
||||
def check_number(func):
|
||||
def wrapper(a, b):
|
||||
if not (isinstance(a, (int, float)) and isinstance(b, (int, float))):
|
||||
print("Input must be numbers")
|
||||
return
|
||||
return func(a, b)
|
||||
return wrapper
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* `check_number` is the decorator.
|
||||
* `func` is the function being decorated.
|
||||
* `wrapper` replaces the original function.
|
||||
* `a` and `b` are the arguments passed to the original function.
|
||||
* `isinstance(a, (int, float))` ensures inputs are numeric.
|
||||
* If validation fails, execution stops.
|
||||
* If validation passes, the original function is called.
|
||||
|
||||
---
|
||||
|
||||
## 4. Using the Decorator with `@` Syntax
|
||||
|
||||
### Code
|
||||
|
||||
```python
|
||||
@check_number
|
||||
def bemola(a, b):
|
||||
try:
|
||||
res = a / b
|
||||
print(res)
|
||||
except ZeroDivisionError:
|
||||
print("Zero Number Detected")
|
||||
except Exception as e:
|
||||
print(f"Error Detected {e}")
|
||||
```
|
||||
|
||||
### What Happens Internally
|
||||
|
||||
This line:
|
||||
|
||||
```python
|
||||
@check_number
|
||||
```
|
||||
|
||||
Is equivalent to:
|
||||
|
||||
```python
|
||||
bemola = check_number(bemola)
|
||||
```
|
||||
|
||||
The function `bemola` is replaced by `wrapper`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Execution Flow
|
||||
|
||||
When calling:
|
||||
|
||||
```python
|
||||
bemola(10, 2)
|
||||
```
|
||||
|
||||
The flow is:
|
||||
|
||||
1. `wrapper(10, 2)` is called
|
||||
2. Inputs are validated
|
||||
3. `func(10, 2)` is executed
|
||||
4. Result is printed
|
||||
|
||||
If calling:
|
||||
|
||||
```python
|
||||
bemola(10, "a")
|
||||
```
|
||||
|
||||
The output will be:
|
||||
|
||||
```text
|
||||
Input must be numbers
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Why Use Decorators?
|
||||
|
||||
Without decorators, input validation would need to be repeated in every function.
|
||||
|
||||
Decorators allow:
|
||||
|
||||
* Reusable logic
|
||||
* Cleaner code
|
||||
* Separation of concerns
|
||||
|
||||
---
|
||||
|
||||
## 7. Limitations in This Example
|
||||
|
||||
* The decorator only works with exactly two arguments.
|
||||
* It does not preserve the original function’s metadata (`__name__`, `__doc__`).
|
||||
|
||||
---
|
||||
|
||||
## 8. Improved Version (Best Practice)
|
||||
|
||||
```python
|
||||
from functools import wraps
|
||||
|
||||
def check_number(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
if not all(isinstance(x, (int, float)) for x in args):
|
||||
print("Input must be numbers")
|
||||
return
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
```
|
||||
|
||||
### Improvements
|
||||
|
||||
* Supports any number of arguments
|
||||
* Preserves function name and documentation
|
||||
* More reusable and professional
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
* Decorators modify function behavior without changing its code
|
||||
* They wrap functions inside another function
|
||||
* `@decorator` is syntactic sugar
|
||||
* Commonly used for validation, logging, and access control
|
||||
* Best practice is to use `*args`, `**kwargs`, and `functools.wraps`
|
||||
Reference in New Issue
Block a user