Python coding
💡 Python Tip #9: Lambda Functions A lambda function is a small anonymous function that can have any number of arguments but only one expression. Lambda functions are useful when you need a simple function for a short period of time. --- Basic Syntax lambda…
🚀 Python Tip #10: The
Counting how many times items appear in a list is a common task.
Instead of writing loops manually, Python provides the
---
Importing
---
Basic Example
Output:
---
Counting Characters
Output:
---
Finding the Most Common Items
Use the
Example:
Output:
---
Why use
✓ Count items with a single line of code
✓ Find the most common elements quickly
✓ Useful for text analysis and data processing
✓ Frequently used in Data Science and Machine Learning
---
Challenge:
Given the following list:
1. Count how many times each number appears.
2. Print the most common number.
3. Which number appears exactly once?
collections.Counter ClassCounting how many times items appear in a list is a common task.
Instead of writing loops manually, Python provides the
Counter class from the collections module.---
Importing
Counterfrom collections import Counter
---
Basic Example
from collections import Counter
fruits = [
"apple",
"banana",
"apple",
"orange",
"banana",
"apple"
]
count = Counter(fruits)
print(count)
Output:
Counter({
'apple': 3,
'banana': 2,
'orange': 1
})---
Counting Characters
from collections import Counter
text = "programming"
count = Counter(text)
print(count)
Output:
Counter({
'g': 2,
'r': 2,
'm': 2,
'p': 1,
'o': 1,
'a': 1,
'i': 1,
'n': 1
})---
Finding the Most Common Items
Use the
most_common() method.Example:
from collections import Counter
votes = [
"Python",
"Java",
"Python",
"C++",
"Python",
"Java"
]
count = Counter(votes)
print(count.most_common(1))
Output:
[('Python', 3)]---
Why use
Counter?✓ Count items with a single line of code
✓ Find the most common elements quickly
✓ Useful for text analysis and data processing
✓ Frequently used in Data Science and Machine Learning
---
Challenge:
Given the following list:
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 5]
1. Count how many times each number appears.
2. Print the most common number.
3. Which number appears exactly once?
Python coding
🚀 Python Tip #10: The collections.Counter Class Counting how many times items appear in a list is a common task. Instead of writing loops manually, Python provides the Counter class from the collections module. --- Importing Counter from collections import…
🔥 Python Tip #11: The
When working with dictionaries, you may need to access a key that doesn't exist.
Instead of checking if the key exists first, Python provides the
---
Basic Example
Output:
Since `"age"
student = {
"name": "Ahmed"
}
student.setdefault("country", "Ethiopia")
print(student)
python
{
'name': 'Ahmed',
'country': 'Ethiopia'
}
python
if "country" not in student:
student["country"] = "Ethiopia"
python
student.setdefault("country", "Ethiopia")
python
words = ["apple", "banana", "apple"]
counts = {}
for word in words:
counts.setdefault(word, 0)
counts[word] += 1
print(counts)
python
{
'apple': 2,
'banana': 1
}
python
cities = [
"Addis Ababa",
"Adama",
"Addis Ababa",
"Hawassa",
"Adama"
]
Use `setdefault()` to count how many times each city appears.
setdefault() Dictionary MethodWhen working with dictionaries, you may need to access a key that doesn't exist.
Instead of checking if the key exists first, Python provides the
setdefault() method.---
Basic Example
student = {
"name": "Ahmed",
"age": 18
}
print(student.setdefault("age", 20))Output:
18
Since `"age"
already exists, its value remains unchanged.
---
Adding a New Key
If the key does not exist, setdefault() creates it using the default value.
Example:
``pythonstudent = {
"name": "Ahmed"
}
student.setdefault("country", "Ethiopia")
print(student)
Output:
python
{
'name': 'Ahmed',
'country': 'Ethiopia'
}
---
Without `setdefault()`
python
if "country" not in student:
student["country"] = "Ethiopia"
---
With `setdefault()`
python
student.setdefault("country", "Ethiopia")
Both produce the same result, but `setdefault()` is shorter and cleaner.
---
Practical Example
Count words without worrying about missing keys.
python
words = ["apple", "banana", "apple"]
counts = {}
for word in words:
counts.setdefault(word, 0)
counts[word] += 1
print(counts)
Output:
python
{
'apple': 2,
'banana': 1
}
---
Why use `setdefault()`?
✓ Avoids `KeyError`
✓ Reduces repetitive code
✓ Automatically creates missing keys
✓ Useful when counting, grouping, or organizing data
---
Challenge:
Given the list:
python
cities = [
"Addis Ababa",
"Adama",
"Addis Ababa",
"Hawassa",
"Adama"
]
`Use `setdefault()` to count how many times each city appears.
Python coding
🔥 Python Tip #11: The setdefault() Dictionary Method When working with dictionaries, you may need to access a key that doesn't exist. Instead of checking if the key exists first, Python provides the setdefault() method. --- Basic Example student = { …
🐍 Python Tip #12: The
Working with files and folders is a common task in Python.
Instead of using traditional string paths, Python provides the
---
Importing
---
Creating a Path
Output:
---
Checking if a File Exists
Output:
or
```python
False
python
from pathlib import Path
file = Path("report.pdf")
print(file.name)
print(file.stem)
print(file.suffix)
python
report.pdf
report
.pdf
python
from pathlib import Path
folder = Path("Projects")
folder.mkdir(exist_ok=True)
python
path = "Projects/" + "Python/" + "main.py"
python
from pathlib import Path
path = Path("Projects") / "Python" / "main.py"
print(path)
python
Projects/Python/main.py
python
Python_Practice
python
notes.txt
text
File found
text
File not found
based on the result.
pathlib ModuleWorking with files and folders is a common task in Python.
Instead of using traditional string paths, Python provides the
pathlib module, which offers a cleaner and more object-oriented approach.---
Importing
Pathfrom pathlib import Path
---
Creating a Path
from pathlib import Path
file = Path("notes.txt")
print(file)
Output:
notes.txt
---
Checking if a File Exists
from pathlib import Path
file = Path("notes.txt")
print(file.exists())
Output:
True
or
```python
False
depending on whether the file exists.
---
Getting File Information
python
from pathlib import Path
file = Path("report.pdf")
print(file.name)
print(file.stem)
print(file.suffix)
Output:
python
report.pdf
report
---
Creating a Folder
python
from pathlib import Path
folder = Path("Projects")
folder.mkdir(exist_ok=True)
The `exist_ok=True` argument prevents an error if the folder already exists.
---
Joining Paths
Instead of writing:
python
path = "Projects/" + "Python/" + "main.py"
Use:
python
from pathlib import Path
path = Path("Projects") / "Python" / "main.py"
print(path)
Output:
python
Projects/Python/main.py
---
Why use `pathlib`?
✓ Cleaner and easier to read
✓ Works across Windows, Linux, and macOS
✓ Object-oriented design
✓ Recommended for modern Python projects
---
Challenge:
Create a program that:
1. Creates a folder named:
python
Python_Practice
2. Checks whether a file named:
python
notes.txt
exists inside that folder.
3. Prints:
text
File found
or
text
File not found
`based on the result.
🤔1
Python coding
🐍 Python Tip #12: The pathlib Module Working with files and folders is a common task in Python. Instead of using traditional string paths, Python provides the pathlib module, which offers a cleaner and more object-oriented approach. --- Importing Path…
🧪 Python Tip #13: Using
When writing unit tests, you don't always want to call real databases, APIs, or external services.
Instead, you can use
---
Importing
---
Why Use
Imagine you have a function that connects to a database.
In a real application, this function might:
- Take several seconds to execute
- Require an internet connection
- Access a real database
- Return different results each time
During testing, this is slow and unreliable.
---
Without
This would execute the real database logic.
---
With
Output:
---
How It Works
Creates a fake version of the function.
Whenever the function is called, it immediately returns the specified value instead of executing the original code.
---
Why use
✓ Makes tests run much faster
✓ No need for a real database or API
✓ Produces predictable results
✓ Essential for professional unit testing
---
Challenge:
Create a
Then print the returned dictionary.
MagicMock for TestingWhen writing unit tests, you don't always want to call real databases, APIs, or external services.
Instead, you can use
MagicMock from Python's unittest.mock module to simulate their behavior.---
Importing
MagicMockfrom unittest.mock import MagicMock
---
Why Use
MagicMock?Imagine you have a function that connects to a database.
In a real application, this function might:
- Take several seconds to execute
- Require an internet connection
- Access a real database
- Return different results each time
During testing, this is slow and unreliable.
---
Without
MagicMockdef get_user_from_db(user_id):
# Slow database query
pass
user = get_user_from_db(1)
print(user)
This would execute the real database logic.
---
With
MagicMockfrom unittest.mock import MagicMock
def get_user_from_db(user_id):
# Slow database query
pass
get_user_from_db = MagicMock(
return_value={
"id": 1,
"name": "John Doe"
}
)
user = get_user_from_db(1)
print(user)
Output:
{'id': 1, 'name': 'John Doe'}---
How It Works
MagicMock(return_value=...)
Creates a fake version of the function.
Whenever the function is called, it immediately returns the specified value instead of executing the original code.
---
Why use
MagicMock?✓ Makes tests run much faster
✓ No need for a real database or API
✓ Produces predictable results
✓ Essential for professional unit testing
---
Challenge:
Create a
MagicMock that simulates a weather API and returns:{
"city": "Addis Ababa",
"temperature": 22,
"condition": "Sunny"
}Then print the returned dictionary.
Python coding
🐍 Python Tip #12: The pathlib Module Working with files and folders is a common task in Python. Instead of using traditional string paths, Python provides the pathlib module, which offers a cleaner and more object-oriented approach. --- Importing Path…
If there is any questions lemme know in the discussion group
Python coding
🧪 Python Tip #13: Using MagicMock for Testing When writing unit tests, you don't always want to call real databases, APIs, or external services. Instead, you can use MagicMock from Python's unittest.mock module to simulate their behavior. --- Importing…
⚡ Python Tip #14: The Walrus Operator (
Introduced in Python 3.8, the walrus operator allows you to assign a value to a variable as part of an expression.
This can make your code shorter and avoid repeating calculations.
---
Without the Walrus Operator
---
With the Walrus Operator
The program behaves exactly the same but requires fewer lines of code.
---
Another Example
Without the walrus operator:
---
With the walrus operator:
---
When Should You Use It?
The walrus operator is useful when:
- A value is needed more than once
- You want to avoid repeating a function call
- You want cleaner and more efficient code
However, don't overuse it. Sometimes a normal assignment is easier to read.
---
Why use the Walrus Operator?
✓ Reduces repeated calculations
✓ Makes some loops cleaner
✓ Can improve performance in certain situations
✓ Useful in data processing and file handling
---
Challenge:
Using the walrus operator, write a program that repeatedly asks the user to enter a number until they type:
Print each number entered before the program exits.
:=)Introduced in Python 3.8, the walrus operator allows you to assign a value to a variable as part of an expression.
This can make your code shorter and avoid repeating calculations.
---
Without the Walrus Operator
name = input("Enter your name: ")
while name != "exit":
print(f"Hello, {name}!")
name = input("Enter your name: ")---
With the Walrus Operator
while (name := input("Enter your name: ")) != "exit":
print(f"Hello, {name}!")The program behaves exactly the same but requires fewer lines of code.
---
Another Example
Without the walrus operator:
numbers = [5, 8, 12, 20]
length = len(numbers)
if length > 3:
print(f"The list contains {length} items.")
---
With the walrus operator:
numbers = [5, 8, 12, 20]
if (length := len(numbers)) > 3:
print(f"The list contains {length} items.")
---
When Should You Use It?
The walrus operator is useful when:
- A value is needed more than once
- You want to avoid repeating a function call
- You want cleaner and more efficient code
However, don't overuse it. Sometimes a normal assignment is easier to read.
---
Why use the Walrus Operator?
✓ Reduces repeated calculations
✓ Makes some loops cleaner
✓ Can improve performance in certain situations
✓ Useful in data processing and file handling
---
Challenge:
Using the walrus operator, write a program that repeatedly asks the user to enter a number until they type:
quit
Print each number entered before the program exits.
Python coding
⚡ Python Tip #14: The Walrus Operator (:=) Introduced in Python 3.8, the walrus operator allows you to assign a value to a variable as part of an expression. This can make your code shorter and avoid repeating calculations. --- Without the Walrus Operator…
💡 Python Tip #15: The
Many beginners confuse
---
Using
The
Example:
Output:
Both lists contain the same values.
---
Using
The
Example:
Output:
Although the values are equal, they are stored as different objects.
---
Same Object Example
Output:
Both variables point to the same object.
---
Checking for
The recommended way to check for
Correct:
Avoid:
Using `is None
x = [10, 20]
y = x
z = [10, 20]
print(x == z)
print(x is z)
print(x is y)
Try to predict the output before running the code.
is vs == OperatorsMany beginners confuse
is and ==, but they have different purposes.---
Using
==The
== operator checks whether two values are equal.Example:
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
Output:
True
Both lists contain the same values.
---
Using
isThe
is operator checks whether two variables refer to the exact same object in memory.Example:
a = [1, 2, 3]
b = [1, 2, 3]
print(a is b)
Output:
False
Although the values are equal, they are stored as different objects.
---
Same Object Example
a = [1, 2, 3]
b = a
print(a is b)
print(a == b)
Output:
True
True
Both variables point to the same object.
---
Checking for
NoneThe recommended way to check for
None is with is.Correct:
name = None
if name is None:
print("No name provided")
Avoid:
if name == None:
print("No name provided")
Using `is None
is the Pythonic approach.
---
Why does this matter?
✓ Prevents subtle bugs
✓ Improves code readability
✓ Follows Python best practices
✓ Commonly used in professional Python projects
---
Challenge:
What will this code print?
``pythonx = [10, 20]
y = x
z = [10, 20]
print(x == z)
print(x is z)
print(x is y)
`Try to predict the output before running the code.
Python coding
💡 Python Tip #15: The is vs == Operators Many beginners confuse is and ==, but they have different purposes. --- Using == The == operator checks whether two values are equal. Example: a = [1, 2, 3] b = [1, 2, 3] print(a == b) Output: True Both lists…
🔥 Python Tip #16: The
When working with files, it's important to close them after you're done.
Python's
---
Without
If an error occurs before
---
With
Once the block ends, Python automatically closes the file.
---
Writing to a File
This creates the file if it doesn't exist, or overwrites it if it does.
---
Appending to a File
Use
---
Why use the
✓ Automatically closes files
✓ Prevents resource leaks
✓ Cleaner and more readable code
✓ Recommended for all file operations
---
Challenge:
Create a program that:
1. Creates a file named:
2. Writes three tasks into the file.
3. Opens the same file and prints all its contents using the
with StatementWhen working with files, it's important to close them after you're done.
Python's
with statement automatically handles this for you.---
Without
withfile = open("notes.txt", "r")
content = file.read()
print(content)
file.close()If an error occurs before
file.close(), the file may remain open.---
With
withwith open("notes.txt", "r") as file:
content = file.read()
print(content)Once the block ends, Python automatically closes the file.
---
Writing to a File
with open("hello.txt", "w") as file:
file.write("Hello, Python!")This creates the file if it doesn't exist, or overwrites it if it does.
---
Appending to a File
Use
"a" mode to add new content without deleting the existing content.with open("hello.txt", "a") as file:
file.write("\nWelcome back!")---
Why use the
with statement?✓ Automatically closes files
✓ Prevents resource leaks
✓ Cleaner and more readable code
✓ Recommended for all file operations
---
Challenge:
Create a program that:
1. Creates a file named:
tasks.txt
2. Writes three tasks into the file.
3. Opens the same file and prints all its contents using the
with statement.
Python coding
🔥 Python Tip #16: The with Statement When working with files, it's important to close them after you're done. Python's with statement automatically handles this for you. --- Without with file = open("notes.txt", "r") content = file.read() print(content)…
🎯 Python Tip #17: The
Introduced in Python 3.10, the
It is similar to the "switch" statement found in many other programming languages.
---
Without
---
With
Output:
---
Matching Strings
---
The Wildcard
The underscore (
Example:
It is equivalent to the
---
Why use
✓ Cleaner than multiple
✓ Easier to read and maintain
✓ Perfect for menus and command handling
✓ Great for pattern matching in modern Python
> Note:
---
Challenge:
Write a program that asks the user to enter one of these commands:
Use `match-case
Invalid command
match-case StatementIntroduced in Python 3.10, the
match-case statement provides a cleaner alternative to long chains of if...elif...else.It is similar to the "switch" statement found in many other programming languages.
---
Without
match-caseday = 3
if day == 1:
print("Monday")
elif day == 2:
print("Tuesday")
elif day == 3:
print("Wednesday")
else:
print("Invalid day")
---
With
match-caseday = 3
match day:
case 1:
print("Monday")
case 2:
print("Tuesday")
case 3:
print("Wednesday")
case _:
print("Invalid day")
Output:
Wednesday
---
Matching Strings
command = "start"
match command:
case "start":
print("Program started")
case "stop":
print("Program stopped")
case "restart":
print("Program restarted")
case _:
print("Unknown command")
---
The Wildcard
_The underscore (
_) acts as the default case.Example:
case _:
print("No match found")
It is equivalent to the
else statement.---
Why use
match-case?✓ Cleaner than multiple
if...elif statements ✓ Easier to read and maintain
✓ Perfect for menus and command handling
✓ Great for pattern matching in modern Python
> Note:
match-case is available only in Python 3.10 and later.---
Challenge:
Write a program that asks the user to enter one of these commands:
add
remove
update
list
Use `match-case
to print the corresponding action. If the command is not recognized, print:
``textInvalid command
`
Python coding
🎯 Python Tip #17: The match-case Statement Introduced in Python 3.10, the match-case statement provides a cleaner alternative to long chains of if...elif...else. It is similar to the "switch" statement found in many other programming languages. --- Without…
🐍 Python Tip #18: The
Most Python programmers know about
The
---
Basic Example
Output:
---
Using
If the loop is interrupted with
Example:
Output:
Notice that
---
Searching Example
The
Output:
---
When is
✓ Searching for an item
✓ Validating data
✓ Avoiding extra boolean variables
✓ Writing cleaner search algorithms
---
Challenge:
Given the following list:
Search for:
If the student exists, print:
Otherwise, use the
for...else StatementMost Python programmers know about
if...else, but fewer know that loops can also have an else block.The
else block executes only if the loop finishes normally (without encountering a break).---
Basic Example
for i in range(5):
print(i)
else:
print("Loop completed successfully!")
Output:
0
1
2
3
4
Loop completed successfully!
---
Using
breakIf the loop is interrupted with
break, the else block will not execute.Example:
for i in range(5):
if i == 3:
break
print(i)
else:
print("Loop completed successfully!")
Output:
0
1
2
Notice that
"Loop completed successfully!" is never printed.---
Searching Example
The
for...else statement is especially useful when searching for an item.numbers = [10, 20, 30, 40]
target = 25
for number in numbers:
if number == target:
print("Number found!")
break
else:
print("Number not found!")
Output:
Number not found!
---
When is
for...else Useful?✓ Searching for an item
✓ Validating data
✓ Avoiding extra boolean variables
✓ Writing cleaner search algorithms
---
Challenge:
Given the following list:
students = ["Ali", "Sara", "John", "Mariam"]
Search for:
"Ahmed"
If the student exists, print:
Student found!
Otherwise, use the
else block to print:Student not found!
Python coding
🐍 Python Tip #18: The for...else Statement Most Python programmers know about if...else, but fewer know that loops can also have an else block. The else block executes only if the loop finishes normally (without encountering a break). --- Basic Example…
💡 Python Tip #19: The
When accessing dictionary values, using square brackets (
Python provides the
---
Using Square Brackets
Output:
---
What Happens if the Key Doesn't Exist?
Output:
The program stops because the key doesn't exist.
---
Using
Output:
Instead of raising an error,
---
Providing a Default Value
You can specify a default value if the key is missing.
Output:
---
Practical Example
Output:
---
Why use
✓ Prevents
✓ Makes your code more reliable
✓ Allows default values
✓ Commonly used when working with JSON data and APIs
---
Challenge:
Given the dictionary:
Use the
- The value of
- The value of
dict.get() MethodWhen accessing dictionary values, using square brackets (
[]) can raise an error if the key doesn't exist.Python provides the
get() method as a safer alternative.---
Using Square Brackets
student = {
"name": "Ali",
"age": 18
}
print(student["name"])Output:
Ali
---
What Happens if the Key Doesn't Exist?
student = {
"name": "Ali"
}
print(student["country"])Output:
KeyError: 'country'
The program stops because the key doesn't exist.
---
Using
get()student = {
"name": "Ali"
}
print(student.get("country"))Output:
None
Instead of raising an error,
get() returns None.---
Providing a Default Value
You can specify a default value if the key is missing.
student = {
"name": "Ali"
}
print(student.get("country", "Unknown"))Output:
Unknown
---
Practical Example
settings = {
"theme": "Dark"
}
theme = settings.get("theme", "Light")
language = settings.get("language", "English")
print(theme)
print(language)Output:
Dark
English
---
Why use
get()?✓ Prevents
KeyError✓ Makes your code more reliable
✓ Allows default values
✓ Commonly used when working with JSON data and APIs
---
Challenge:
Given the dictionary:
book = {
"title": "Python Basics",
"author": "Yehya"
}Use the
get() method to print:- The value of
"title"- The value of
"price" (use "Not Available" as the default value)
Python coding
💡 Python Tip #19: The dict.get() Method When accessing dictionary values, using square brackets ([]) can raise an error if the key doesn't exist. Python provides the get() method as a safer alternative. --- Using Square Brackets student = { "name":…
🚀 Python Tip #20: The
When working with dictionaries, you often need to check whether a key already exists before using it.
Python's
---
Importing
---
Without
Output:
---
With
Output:
---
Grouping Data
Example:
Output:
---
Common Default Types
---
Why use
✓ Eliminates repetitive key checks
✓ Makes code cleaner and shorter
✓ Perfect for counting and grouping data
✓ Frequently used in Data Science and competitive programming
---
Challenge:
Given the following list:
Use `defaultdict(list)
{
'Mammal': ['Lion', 'Tiger'],
'Bird': ['Eagle', 'Parrot'],
'Fish': ['Salmon']
}
collections.defaultdict ClassWhen working with dictionaries, you often need to check whether a key already exists before using it.
Python's
defaultdict automatically creates missing keys with a default value.---
Importing
defaultdictfrom collections import defaultdict
---
Without
defaultdictscores = {}
for name in ["Ali", "Sara", "Ali"]:
if name not in scores:
scores[name] = 0
scores[name] += 1
print(scores)Output:
{'Ali': 2, 'Sara': 1}---
With
defaultdictfrom collections import defaultdict
scores = defaultdict(int)
for name in ["Ali", "Sara", "Ali"]:
scores[name] += 1
print(dict(scores))
Output:
{'Ali': 2, 'Sara': 1}---
Grouping Data
defaultdict is also useful for grouping values.Example:
from collections import defaultdict
students = defaultdict(list)
students["Grade A"].append("Ali")
students["Grade A"].append("Sara")
students["Grade B"].append("John")
print(dict(students))
Output:
{
'Grade A': ['Ali', 'Sara'],
'Grade B': ['John']
}---
Common Default Types
defaultdict(int) # Default value: 0
defaultdict(float) # Default value: 0.0
defaultdict(str) # Default value: ""
defaultdict(list) # Default value: []
defaultdict(set) # Default value: set()
---
Why use
defaultdict?✓ Eliminates repetitive key checks
✓ Makes code cleaner and shorter
✓ Perfect for counting and grouping data
✓ Frequently used in Data Science and competitive programming
---
Challenge:
Given the following list:
animals = [
("Mammal", "Lion"),
("Bird", "Eagle"),
("Mammal", "Tiger"),
("Bird", "Parrot"),
("Fish", "Salmon")
]
Use `defaultdict(list)
to group the animals by their category.
Expected Output:
``python{
'Mammal': ['Lion', 'Tiger'],
'Bird': ['Eagle', 'Parrot'],
'Fish': ['Salmon']
}
`⚡ Python Tip #21: The
Some functions perform the same calculations repeatedly, which can slow down your program.
Python provides the
---
Importing
---
Without
This works, but it recalculates the same values many times, making it slow.
---
With
The result is the same, but the function runs much faster because previous results are stored in memory.
---
How It Works
- `@lru_cache
from functools import lru_cache
@lru_cache(maxsize=None)
def square(n):
print("Calculating...")
return n ** 2
print(square(5))
print(square(5))
python
Calculating...
25
25
Notice that `"Calculating..."` is printed only once because the second call uses the cached result.
---
Why use `lru_cache`?
✓ Speeds up repeated function calls
✓ Avoids unnecessary calculations
✓ Simple to use with a single decorator
✓ Commonly used in recursion, dynamic programming, and optimization
---
Challenge:
Create a recursive function that calculates the factorial of a number and use `@lru_cache(maxsize=None)` to cache its results.
Test your function by calling it multiple times with the same input and observe how caching improves efficiency.
functools.lru_cache DecoratorSome functions perform the same calculations repeatedly, which can slow down your program.
Python provides the
lru_cache decorator to automatically remember previous results and reuse them.---
Importing
lru_cachefrom functools import lru_cache
---
Without
lru_cachedef fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(35))
This works, but it recalculates the same values many times, making it slow.
---
With
lru_cachefrom functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(35))
The result is the same, but the function runs much faster because previous results are stored in memory.
---
How It Works
@lru_cache(maxsize=None)
- `@lru_cache
enables caching.
- maxsize=None means there is no limit on the number of cached results.
---
Another Example
``pythonfrom functools import lru_cache
@lru_cache(maxsize=None)
def square(n):
print("Calculating...")
return n ** 2
print(square(5))
print(square(5))
Output:
python
Calculating...
25
25
`Notice that `"Calculating..."` is printed only once because the second call uses the cached result.
---
Why use `lru_cache`?
✓ Speeds up repeated function calls
✓ Avoids unnecessary calculations
✓ Simple to use with a single decorator
✓ Commonly used in recursion, dynamic programming, and optimization
---
Challenge:
Create a recursive function that calculates the factorial of a number and use `@lru_cache(maxsize=None)` to cache its results.
Test your function by calling it multiple times with the same input and observe how caching improves efficiency.
Python coding
⚡ Python Tip #21: The functools.lru_cache Decorator Some functions perform the same calculations repeatedly, which can slow down your program. Python provides the lru_cache decorator to automatically remember previous results and reuse them. --- Importing…
🐍 Python Tip #22: The
When creating classes that mainly store data, Python provides the
It automatically generates methods like
---
Importing
---
Without
---
With
Output:
---
Comparing Objects
Output:
Without
---
Using Default Values
Output:
---
Why use
✓ Less boilerplate code
✓ Automainitcreates
✓ Improves readability
✓ Ideal for configuration objects, API responses, and data models
---
Challenge:
Create a
Then create an object and print it.
dataclass DecoratorWhen creating classes that mainly store data, Python provides the
@dataclass decorator to reduce boilerplate code.It automatically generates methods like
__init__(), __repr__(), and __eq__().---
Importing
dataclassfrom dataclasses import dataclass
---
Without
@dataclassclass Student:
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
student = Student("Ali", 18, "A")
print(student.name)
print(student.age)
print(student.grade)
---
With
@dataclassfrom dataclasses import dataclass
@dataclass
class Student:
name: str
age: int
grade: str
student = Student("Ali", 18, "A")
print(student)
Output:
Student(name='Ali', age=18, grade='A')
---
Comparing Objects
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
p1 = Point(2, 3)
p2 = Point(2, 3)
print(p1 == p2)
Output:
True
Without
@dataclass, these objects would normally not be considered equal unless eqplemented __eq__() yourself.---
Using Default Values
from dataclasses import dataclass
@dataclass
class User:
username: str
active: bool = True
user = User("Yehya")
print(user)
Output:
User(username='Yehya', active=True)
---
Why use
@dataclass?✓ Less boilerplate code
✓ Automainitcreates
__init__() and other methods ✓ Improves readability
✓ Ideal for configuration objects, API responses, and data models
---
Challenge:
Create a
Book dataclass with the following fields:title: str
author: str
pages: int
price: float
Then create an object and print it.
Python coding
🐍 Python Tip #22: The dataclass Decorator When creating classes that mainly store data, Python provides the @dataclass decorator to reduce boilerplate code. It automatically generates methods like __init__(), __repr__(), and __eq__(). --- Importing dataclass…
🚀 Python Tip #23: The
The
It is useful for generating all possible combinations.
---
Importing
---
Basic Example
Output:
---
Converting to a List
If you want to store all combinations:
Output:
---
Repeating an Iterable
Use the
Output:
---
Why use
✓ Generates every possible combination automatically
✓ Eliminates nested loops
✓ Useful for brute-force algorithms and testing
✓ Commonly used in Data Science, AI, and combinatorial problems
---
Challenge:
Given the following lists:
Use `itertools.product()` to generate every possible outfit combination.
itertools.product() FunctionThe
product() function from Python's itertools module returns the Cartesian product of two or more iterables.It is useful for generating all possible combinations.
---
Importing
productfrom itertools import product
---
Basic Example
from itertools import product
colors = ["Red", "Blue"]
sizes = ["S", "M", "L"]
result = product(colors, sizes)
for item in result:
print(item)
Output:
('Red', 'S')
('Red', 'M')
('Red', 'L')
('Blue', 'S')
('Blue', 'M')
('Blue', 'L')---
Converting to a List
If you want to store all combinations:
from itertools import product
letters = ["A", "B"]
numbers = [1, 2, 3]
result = list(product(letters, numbers))
print(result)
Output:
[('A', 1), ('A', 2), ('A', 3), ('B', 1), ('B', 2), ('B', 3)]---
Repeating an Iterable
Use the
repeat parameter to generate combinations from the same iterable.from itertools import product
result = list(product([0, 1], repeat=3))
print(result)
Output:
[(0, 0, 0),
(0, 0, 1),
(0, 1, 0),
(0, 1, 1),
(1, 0, 0),
(1, 0, 1),
(1, 1, 0),
(1, 1, 1)]
---
Why use
itertools.product()?✓ Generates every possible combination automatically
✓ Eliminates nested loops
✓ Useful for brute-force algorithms and testing
✓ Commonly used in Data Science, AI, and combinatorial problems
---
Challenge:
Given the following lists:
shirts = ["Black", "White"]
pants = ["Jeans", "Shorts"]
shoes = ["Sneakers", "Boots"]
Use `itertools.product()` to generate every possible outfit combination.
Python coding
🚀 Python Tip #23: The itertools.product() Function The product() function from Python's itertools module returns the Cartesian product of two or more iterables. It is useful for generating all possible combinations. --- Importing product from itertools…
🚀 Python Tip #24: The
The
It is useful for organizing and summarizing data.
---
Importing
---
Basic Example
Output:
---
Grouping Strings
Output:
Notice that the last
---
Grouping Objects
Output:
---
Important Note
If your data is not already sorted by the grouping key, sort it first.
This ensures that all items with the same key appear together.
---
Why use
✓ Groups consecutive data efficiently
✓ Useful for reports and summaries
✓ Works well with sorted datasets
✓ Commonly used in data analysis and log processing
---
Challenge:
Given the following list:
Sort the list and use
Expected Output:
itertools.groupby() FunctionThe
groupby() function from Python's itertools module groups consecutive items that have the same key.It is useful for organizing and summarizing data.
---
Importing
groupbyfrom itertools import groupby
---
Basic Example
from itertools import groupby
numbers = [1, 1, 2, 2, 2, 3, 3]
for key, group in groupby(numbers):
print(key, list(group))
Output:
1 [1, 1]
2 [2, 2, 2]
3 [3, 3]
---
Grouping Strings
from itertools import groupby
text = "aaabbbbccdaa"
for letter, group in groupby(text):
print(letter, len(list(group)))
Output:
a 3
b 4
c 2
d 1
a 2
Notice that the last
"a" forms a new group because groupby() only groups consecutive items.---
Grouping Objects
from itertools import groupby
students = [
("Ali", "A"),
("Sara", "A"),
("John", "B"),
("Mariam", "B")
]
for grade, group in groupby(students, key=lambda x: x[1]):
print(grade, list(group))
Output:
A [('Ali', 'A'), ('Sara', 'A')]
B [('John', 'B'), ('Mariam', 'B')]---
Important Note
If your data is not already sorted by the grouping key, sort it first.
students = sorted(students, key=lambda x: x[1])
This ensures that all items with the same key appear together.
---
Why use
groupby()?✓ Groups consecutive data efficiently
✓ Useful for reports and summaries
✓ Works well with sorted datasets
✓ Commonly used in data analysis and log processing
---
Challenge:
Given the following list:
words = [
"apple",
"ant",
"banana",
"ball",
"cat",
"car"
]
Sort the list and use
groupby() to group the words by their first letter.Expected Output:
a ['ant', 'apple']
b ['ball', 'banana']
c ['car', 'cat']
Python coding
🚀 Python Tip #24: The itertools.groupby() Function The groupby() function from Python's itertools module groups consecutive items that have the same key. It is useful for organizing and summarizing data. --- Importing groupby from itertools import groupby…
⚡ Python Tip #25: The
When optimizing your code, don't guess which approach is faster—measure it.
Python's
---
Importing
---
Basic Example
Output:
(The exact time will vary depending on your computer.)
---
Comparing Two Approaches
Method 1
Method 2
By comparing the results, you can determine which approach is faster.
---
Using a Function
---
Why use
✓ Measures execution time accurately
✓ Helps optimize performance
✓ Ideal for benchmarking different solutions
✓ Widely used by professional Python developers
---
Challenge:
Compare the execution time of these two methods for creating a list of numbers from
Method 1:
Method 2:
Use the
timeit ModuleWhen optimizing your code, don't guess which approach is faster—measure it.
Python's
timeit module helps you accurately measure the execution time of small code snippets.---
Importing
timeitimport timeit
---
Basic Example
import timeit
execution_time = timeit.timeit(
"sum(range(100))",
number=10000
)
print(execution_time)
Output:
0.0...
(The exact time will vary depending on your computer.)
---
Comparing Two Approaches
Method 1
import timeit
list_time = timeit.timeit(
"[x for x in range(1000)]",
number=10000
)
print(list_time)
Method 2
import timeit
loop_time = timeit.timeit(
"""
numbers = []
for x in range(1000):
numbers.append(x)
""",
number=10000
)
print(loop_time)
By comparing the results, you can determine which approach is faster.
---
Using a Function
import timeit
def square():
return [x ** 2 for x in range(1000)]
print(timeit.timeit(square, number=1000))
---
Why use
timeit?✓ Measures execution time accurately
✓ Helps optimize performance
✓ Ideal for benchmarking different solutions
✓ Widely used by professional Python developers
---
Challenge:
Compare the execution time of these two methods for creating a list of numbers from
0 to 9999:Method 1:
[x for x in range(10000)]
Method 2:
numbers = []
for i in range(10000):
numbers.append(i)
Use the
timeit module to determine which method is faster on your machine.
Python coding
⚡ Python Tip #25: The timeit Module When optimizing your code, don't guess which approach is faster—measure it. Python's timeit module helps you accurately measure the execution time of small code snippets. --- Importing timeit import timeit --- Basic…
🐍 Python Tip #26: The
Sometimes you expect an exception to occur and want to ignore it safely.
Python's
---
Importing
---
Without
This works, but it becomes repetitive if used frequently.
---
With
If `data.txt
from contextlib import suppress
with suppress(FileNotFoundError, ZeroDivisionError):
print(10 / 0)
python
temp.txt
Use `contextlib.suppress()` so that if the file does not exist, the program continues without raising an error.
contextlib.suppress() Context ManagerSometimes you expect an exception to occur and want to ignore it safely.
Python's
contextlib.suppress() provides a clean way to suppress specific exceptions without using a try...except block.---
Importing
suppressfrom contextlib import suppress
---
Without
suppress()try:
with open("data.txt") as file:
print(file.read())
except FileNotFoundError:
pass
This works, but it becomes repetitive if used frequently.
---
With
suppress()from contextlib import suppress
with suppress(FileNotFoundError):
with open("data.txt") as file:
print(file.read())
If `data.txt
doesn't exist, no error is raised and the program continues.
---
Suppressing Multiple Exceptions
You can suppress more than one exception.
``pythonfrom contextlib import suppress
with suppress(FileNotFoundError, ZeroDivisionError):
print(10 / 0)
The program continues running without crashing.
---
When Should You Use It?
Use `suppress()` only when an exception is expected and safely ignorable.
Examples include:
- Removing a file that may not exist
- Opening an optional configuration file
- Handling optional resources
Avoid using it to hide unexpected errors, as this can make debugging difficult.
---
Why use `contextlib.suppress()`?
✓ Cleaner than empty `try...except` blocks
✓ Makes your code more readable
✓ Handles expected exceptions gracefully
✓ Useful in scripts, automation, and file management
---
Challenge:
Write a program that attempts to delete a file named:
python
temp.txt
`Use `contextlib.suppress()` so that if the file does not exist, the program continues without raising an error.
Python coding
🐍 Python Tip #26: The contextlib.suppress() Context Manager Sometimes you expect an exception to occur and want to ignore it safely. Python's contextlib.suppress() provides a clean way to suppress specific exceptions without using a try...except block. …
💡 Python Tip #27: The
Searching for files manually can be tedious, especially in large directories.
Python's
---
Importing
---
Finding All Python Files
Output:
The `*.py
from pathlib import Path
folder = Path("documents")
for file in folder.glob("*.txt"):
print(file.name)
python
from pathlib import Path
folder = Path(".")
for file in folder.rglob("*.py"):
print(file)
python
*.py # All Python files
*.txt # All text files
*.jpg # All JPEG images
data_* # Files starting with "data_"
*.* # All files with an extension
---
Why use `glob()`?
✓ Easily search for files using patterns
✓ Eliminates manual file filtering
✓ Works across different operating systems
✓ Useful for automation, backups, and data processing
---
Challenge:
Write a program that searches the current directory for all PDF files.
Then print:
- The file name
- The file extension
- The full file path
using the `pathlib` module.
pathlib.Path.glob() MethodSearching for files manually can be tedious, especially in large directories.
Python's
pathlib module provides the glob() method to easily find files using patterns.---
Importing
Pathfrom pathlib import Path
---
Finding All Python Files
from pathlib import Path
folder = Path(".")
for file in folder.glob("*.py"):
print(file)
Output:
main.py
app.py
utils.py
The `*.py
pattern matches all files ending with .py.
---
Finding Text Files
``pythonfrom pathlib import Path
folder = Path("documents")
for file in folder.glob("*.txt"):
print(file.name)
This prints the names of all text files in the `documents` folder.
---
Searching Recursively
Use `rglob()` to search through all subfolders.
python
from pathlib import Path
folder = Path(".")
for file in folder.rglob("*.py"):
print(file)
This finds every Python file in the current directory and all of its subdirectories.
---
Common Patterns
python
*.py # All Python files
*.txt # All text files
*.jpg # All JPEG images
data_* # Files starting with "data_"
*.* # All files with an extension
`---
Why use `glob()`?
✓ Easily search for files using patterns
✓ Eliminates manual file filtering
✓ Works across different operating systems
✓ Useful for automation, backups, and data processing
---
Challenge:
Write a program that searches the current directory for all PDF files.
Then print:
- The file name
- The file extension
- The full file path
using the `pathlib` module.
Python coding
💡 Python Tip #27: The pathlib.Path.glob() Method Searching for files manually can be tedious, especially in large directories. Python's pathlib module provides the glob() method to easily find files using patterns. --- Importing Path from pathlib import…
🚀 Python Tip #28: The
Python lists are excellent for most tasks, but they become inefficient when adding or removing items from the beginning.
The
---
Importing
---
Creating a Deque
Output:
---
Adding Elements
Append to the right:
Output:
Append to the left:
Output:
---
Removing Elements
Remove from the right:
Remove from the left:
Example:
Output:
---
Limiting the Size
A deque can have a maximum length.
Output:
The oldest item is automatically removed when the limit is exceeded.
---
Why use
✓ Fast insertions and deletions from both ends
✓ More efficient than lists for queue operations
✓ Supports fixed-size queues with
✓ Commonly used in task scheduling, caching, and breadth-first search (BFS)
---
Challenge:
Create a deque with a maximum length of
Then:
1. Add the numbers
2. Print the deque.
3. Explain why the first two numbers are no longer present.
collections.deque ClassPython lists are excellent for most tasks, but they become inefficient when adding or removing items from the beginning.
The
deque (double-ended queue) from the collections module is designed for fast insertions and deletions from both ends.---
Importing
dequefrom collections import deque
---
Creating a Deque
from collections import deque
queue = deque([1, 2, 3])
print(queue)
Output:
deque([1, 2, 3])
---
Adding Elements
Append to the right:
from collections import deque
queue = deque([1, 2, 3])
queue.append(4)
print(queue)
Output:
deque([1, 2, 3, 4])
Append to the left:
queue.appendleft(0)
print(queue)
Output:
deque([0, 1, 2, 3, 4])
---
Removing Elements
Remove from the right:
queue.pop()
Remove from the left:
queue.popleft()
Example:
from collections import deque
queue = deque([1, 2, 3])
queue.popleft()
print(queue)
Output:
deque([2, 3])
---
Limiting the Size
A deque can have a maximum length.
from collections import deque
history = deque(maxlen=3)
history.append("Page 1")
history.append("Page 2")
history.append("Page 3")
history.append("Page 4")
print(history)
Output:
deque(['Page 2', 'Page 3', 'Page 4'])
The oldest item is automatically removed when the limit is exceeded.
---
Why use
deque?✓ Fast insertions and deletions from both ends
✓ More efficient than lists for queue operations
✓ Supports fixed-size queues with
maxlen ✓ Commonly used in task scheduling, caching, and breadth-first search (BFS)
---
Challenge:
Create a deque with a maximum length of
5.Then:
1. Add the numbers
1 through 7.2. Print the deque.
3. Explain why the first two numbers are no longer present.