decorators doc

This commit is contained in:
RadinPirouz
2026-02-04 21:23:37 +03:30
parent 1b5d863dfa
commit e2711d6591

182
Docs/Basic/08-decorators.md Normal file
View 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 functions 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`