Compare commits

..

3 Commits

Author SHA1 Message Date
RadinPirouz
b251ae7e2e added standard lib doc 2026-02-07 17:17:25 +03:30
RadinPirouz
e2711d6591 decorators doc 2026-02-04 21:23:37 +03:30
RadinPirouz
1b5d863dfa error handeling doc 2026-02-04 21:23:03 +03:30
3 changed files with 667 additions and 0 deletions

View File

@@ -0,0 +1,219 @@
# 06 Error Handling, Linting, Formatting, and Testing in Python
This document explains how Python handles runtime errors, how to write safer code using `try / except`, and how to improve code quality using **linting**, **formatting**, and **unit testing** tools.
---
## 1. Error Handling with `try / except`
Python uses `try / except` blocks to handle runtime errors gracefully without crashing the program.
### Example
```python
def abbas(a, b):
try:
res = a / b
print(res)
except ZeroDivisionError:
print("Zero Number Detected")
except Exception as e:
print(f"Error Detected {e}")
abbas(1, 0)
```
### Explanation
* The code inside `try` is executed first.
* If no error occurs, the result is printed.
* If `b` is `0`, a `ZeroDivisionError` is raised.
* The specific `ZeroDivisionError` block runs first.
* Any other error is caught by the generic `Exception` block.
### Key Rule
* Always catch **specific exceptions first**.
* Use `Exception` only as a fallback.
---
## 2. Full `try / except` Structure
Python supports additional blocks for more control.
### Syntax
```python
try:
# code that may raise an error
except:
# runs if an error occurs
else:
# runs if no error occurs
finally:
# always runs
```
### Explanation
* `try`: code that may fail
* `except`: handles errors
* `else`: runs only if no exception occurred
* `finally`: runs no matter what (used for cleanup)
---
## 3. Linting with `pylint`
Linting analyzes code for:
* Syntax errors
* Style problems
* Bad practices
### Basic Command
```bash
pylint main.py
```
### Detailed Report
```bash
pylint --report y main.py
```
### Explanation
* `pylint` gives a score and suggestions.
* Helps maintain readable and maintainable code.
* Commonly used in professional Python projects.
---
## 4. Code Formatting with `black`
`black` is an automatic code formatter that enforces a consistent style.
### Command
```bash
black main.py
```
### Explanation
* Reformats code automatically.
* Removes style debates.
* Safe and widely used.
---
## 5. Unit Testing with `unittest`
Unit tests verify that individual parts of code behave as expected.
---
### Application Code
#### `abbas.py`
```python
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}")
```
---
### Test Code
#### `abbas_test.py`
```python
import unittest
from abbas import bemola
class TestAbbas(unittest.TestCase):
def test_bemola(self):
a = 10
b = 2
self.assertEqual(bemola(a, b), 5)
if __name__ == "__main__":
unittest.main()
```
---
### Explanation
#### `unittest.TestCase`
* Base class for writing test cases.
#### Test Method
```python
def test_bemola(self):
```
* Test methods must start with `test_`.
#### Assertion
```python
self.assertEqual(bemola(a, b), 5)
```
* Checks if the function returns the expected result.
---
### Important Note (Design Issue)
The function `bemola` **prints** the result but does not return it.
```python
print(res)
```
This causes the test to fail because the function returns `None`.
#### Correct Implementation
```python
def bemola(a, b):
try:
return a / b
except ZeroDivisionError:
return "Zero Number Detected"
except Exception as e:
return f"Error Detected {e}"
```
This version:
* Returns values instead of printing
* Is testable
* Follows best practices
---
## Summary
* `try / except` prevents program crashes
* `else` runs only when no error occurs
* `finally` always runs
* `pylint` improves code quality
* `black` enforces formatting
* `unittest` verifies correctness
* Functions should **return values**, not print them, when tested

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`

View File

@@ -0,0 +1,266 @@
# 09 Python Standard Library
This document introduces some of the most commonly used **Python standard library** modules:
* `datetime`
* `math`
* `random`
* `decimal`
These modules come bundled with Python and require no external installation.
---
## 1. Date and Time with `datetime`
The `datetime` module provides classes for working with dates and times.
---
### Working with Dates
#### Code
```python
import datetime
date_1 = datetime.date(2026, 1, 1)
print(date_1.year)
print(date_1.month)
print(date_1.day)
print(date_1.weekday)
print(date_1.ctime)
```
#### Explanation
* `datetime.date(year, month, day)` creates a date object.
* `.year`, `.month`, `.day` access individual components.
#### Important Note
```python
date_1.weekday()
```
* Returns the day of the week as an integer:
* Monday = 0
* Sunday = 6
```python
date_1.ctime()
```
* Returns a human-readable string representation of the date.
---
### Working with Time
#### Code
```python
time_1 = datetime.time(12, 12)
print(time_1.hour)
print(time_1.min)
```
#### Explanation
* `datetime.time(hour, minute)` creates a time object.
* `.hour` returns the hour.
* `.minute` returns the minute.
---
### Working with Date and Time Together
#### Code
```python
abbas_birth = datetime.datetime(2026, 1, 1, 12, 12)
today = datetime.date.today()
now = datetime.datetime.now()
diff_time = now - abbas_birth
```
#### Explanation
* `datetime.datetime` includes both date and time.
* `date.today()` returns todays date.
* `datetime.now()` returns the current date and time.
* Subtracting two `datetime` objects returns a `timedelta`.
---
## 2. Mathematical Operations with `math`
The `math` module provides advanced mathematical functions and constants.
---
### Mathematical Constants
```python
import math
print(math.pi)
print(math.e)
print(math.inf)
```
* `math.pi`: π constant
* `math.e`: Eulers number
* `math.inf`: infinity
---
### Power and Rounding
```python
print(math.pow(2, 3))
print(round(4.2))
print(round(4.8))
```
* `math.pow(a, b)` returns `a` raised to the power of `b`.
* `round()` rounds to the nearest integer.
---
### Floor and Ceil
```python
print(math.floor(4.2))
print(math.floor(4.9))
print(math.ceil(4.2))
print(math.ceil(4.9))
```
* `floor`: rounds down
* `ceil`: rounds up
---
### Logarithms
```python
print(math.log(100, 10))
```
* Returns the logarithm of 100 with base 10.
---
## 3. Random Values with `random`
The `random` module is used to generate pseudo-random values.
---
### Random Numbers
```python
import random
print(random.randint(1, 6))
print(random.random())
```
* `randint(a, b)`: random integer between `a` and `b` (inclusive)
* `random()`: random float between `0` and `1`
---
### Random Selection
```python
number_list = list(range(15))
print(random.choice(number_list))
char_list = ['a', 'm', 's']
print(random.choice(char_list))
```
* `choice()` selects a random element from a sequence.
---
### Shuffling
```python
random.shuffle(number_list)
print(number_list)
```
* `shuffle()` randomly rearranges the list in place.
---
## 4. Decimal Precision with `decimal`
The `decimal` module provides precise decimal arithmetic, avoiding floating-point errors.
---
### Decimal Context
```python
import decimal
print(decimal.getcontext())
```
* Shows current precision and rounding settings.
---
### Float vs Decimal
```python
print(decimal.Decimal(0.1))
print(decimal.Decimal('0.1'))
```
* Passing a float carries floating-point error.
* Passing a string preserves exact value.
---
### Precision Comparison
```python
print(0.1 + 0.2 == 0.3)
```
Returns `False` due to floating-point precision issues.
```python
print(decimal.Decimal(0.1) + decimal.Decimal(0.2) == decimal.Decimal(0.3))
```
Still `False` because the floats are imprecise.
```python
print(decimal.Decimal('0.1') + decimal.Decimal('0.2') == decimal.Decimal('0.3'))
```
Returns `True` because strings preserve precision.
---
## Summary
* `datetime` handles dates and times
* `math` provides mathematical constants and functions
* `random` generates pseudo-random values
* `decimal` solves floating-point precision problems
* Always use strings when creating `Decimal` values