Python coding
π‘ Python Tip #63: The functools.cached_property Decorator The cached_property decorator from Python's functools module computes a property only once. After the first access, the computed value is stored (cached), so future accesses return the cached resultβ¦
π Python Tip #64: The
The
It improves code readability and helps static type checkers detect errors.
---
Importing
---
Creating a
Output:
---
Accessing Values
Output:
---
Optional Keys
You can make keys optional using
Output:
The `age
student = {
"name": "Ali",
"age": 18
}
python
Book
python
title: str
author: str
pages: int
price: float
python
publisher
using `total=False`.
typing.TypedDict ClassThe
TypedDict class from Python's typing module lets you define dictionaries with specific keys and value types.It improves code readability and helps static type checkers detect errors.
---
Importing
TypedDictfrom typing import TypedDict
---
Creating a
TypedDictfrom typing import TypedDict
class Student(TypedDict):
name: str
age: int
grade: str
student: Student = {
"name": "Ali",
"age": 18,
"grade": "A"
}
print(student)
Output:
{
'name': 'Ali',
'age': 18,
'grade': 'A'
}---
Accessing Values
from typing import TypedDict
class Employee(TypedDict):
name: str
salary: float
employee: Employee = {
"name": "John",
"salary": 4500.0
}
print(employee["name"])
print(employee["salary"])
Output:
John
4500.0
---
Optional Keys
You can make keys optional using
total=False.from typing import TypedDict
class User(TypedDict, total=False):
name: str
age: int
city: str
user: User = {
"name": "Yehya"
}
print(user)
Output:
{
'name': 'Yehya'
}The `age
and city keys are optional.
---
Why use TypedDict?
Without TypedDict:
``pythonstudent = {
"name": "Ali",
"age": 18
}
There's no indication of the expected structure.
With `TypedDict`, the expected keys and value types are clearly defined, making your code easier to understand and maintain.
---
Why use `TypedDict`?
β Defines structured dictionaries with type hints
β Improves code readability
β Helps static type checkers catch mistakes
β Commonly used in APIs, configuration files, and JSON-like data structures
---
Challenge:
Create a `TypedDict` named:
python
Book
with the following fields:
python
title: str
author: str
pages: int
price: float
Then:
1. Create a `Book` dictionary.
2. Print each value.
3. Add an optional field named:
python
publisher
`using `total=False`.
Python coding
π Python Tip #64: The typing.TypedDict Class The TypedDict class from Python's typing module lets you define dictionaries with specific keys and value types. It improves code readability and helps static type checkers detect errors. --- Importing TypedDictβ¦
π Python Tip #65: The
The
This is known as structural typing or duck typing.
---
Importing
---
Creating a Protocol
The `Speaker
from typing import Protocol
class Speaker(Protocol):
def speak(self) -> str:
...
class Person:
def speak(self) -> str:
return "Hello!"
person = Person()
print(person.speak())
python
Hello!
python
from typing import Protocol
class Animal(Protocol):
def sound(self) -> str:
...
class Dog:
def sound(self):
return "Woof!"
class Cat:
def sound(self):
return "Meow!"
def make_sound(animal: Animal):
print(animal.sound())
make_sound(Dog())
make_sound(Cat())
python
Woof!
Meow!
python
Drawable
python
draw()
python
Circle
Rectangle
2. Implement the `draw()` method in both classes.
3. Write a function that accepts any `Drawable` object and calls its `draw()` method.
typing.Protocol ClassThe
Protocol class from Python's typing module allows you to define a set of required methods and attributes without requiring inheritance.This is known as structural typing or duck typing.
---
Importing
Protocolfrom typing import Protocol
---
Creating a Protocol
from typing import Protocol
class Speaker(Protocol):
def speak(self) -> str:
...
The `Speaker
protocol requires a speak() method that returns a string.
---
Implementing the Protocol
``pythonfrom typing import Protocol
class Speaker(Protocol):
def speak(self) -> str:
...
class Person:
def speak(self) -> str:
return "Hello!"
person = Person()
print(person.speak())
Output:
python
Hello!
Notice that `Person` does **not** inherit from `Speaker`, but it still satisfies the protocol because it implements the required method.
---
Using Protocol in Functions
python
from typing import Protocol
class Animal(Protocol):
def sound(self) -> str:
...
class Dog:
def sound(self):
return "Woof!"
class Cat:
def sound(self):
return "Meow!"
def make_sound(animal: Animal):
print(animal.sound())
make_sound(Dog())
make_sound(Cat())
Output:
python
Woof!
Meow!
Both classes work because they provide the required `sound()` method.
---
Why use `Protocol`?
β Enables structural typing (duck typing)
β No need for explicit inheritance
β Makes code more flexible and reusable
β Commonly used in libraries, frameworks, APIs, and large Python projects
---
Challenge:
Create a protocol named:
python
Drawable
with a method:
python
draw()
Then:
1. Create two classes:
python
Circle
Rectangle
`2. Implement the `draw()` method in both classes.
3. Write a function that accepts any `Drawable` object and calls its `draw()` method.
Python coding
π Python Tip #65: The typing.Protocol Class The Protocol class from Python's typing module allows you to define a set of required methods and attributes without requiring inheritance. This is known as structural typing or duck typing. --- Importing Protocolβ¦
π Python Tip #66: The
The
This improves type safety and makes your code easier to understand.
---
Importing
---
Basic Example
Output:
The variable can only have one of the specified values.
---
Using
Output:
Passing any other value would be considered a type error by static type checkers.
---
Restricting Numeric Values
Output:
---
Using Multiple
Output:
---
Why use
β Restricts values to predefined choices
β Improves code readability and maintainability
β Helps static type checkers detect invalid values
β Commonly used in APIs, configuration options, and application settings
---
Challenge:
Create a function named:
The function should accept only these values:
using `Literal
"English"
and print the selected language.
typing.Literal TypeThe
Literal type from Python's typing module allows you to restrict a variable or function parameter to specific, predefined values.This improves type safety and makes your code easier to understand.
---
Importing
Literalfrom typing import Literal
---
Basic Example
from typing import Literal
Status = Literal["pending", "running", "completed"]
status: Status = "running"
print(status)
Output:
running
The variable can only have one of the specified values.
---
Using
Literal in Functionsfrom typing import Literal
def set_theme(
theme: Literal["light", "dark"]
):
print(f"Theme: {theme}")
set_theme("dark")
Output:
Theme: dark
Passing any other value would be considered a type error by static type checkers.
---
Restricting Numeric Values
from typing import Literal
def roll_dice(
sides: Literal[4, 6, 8, 10, 12, 20]
):
print(f"Rolling a {sides}-sided dice.")
roll_dice(20)
Output:
Rolling a 20-sided dice.
---
Using Multiple
Literal Valuesfrom typing import Literal
Direction = Literal[
"north",
"south",
"east",
"west"
]
def move(direction: Direction):
print(f"Moving {direction}")
move("north")
Output:
Moving north
---
Why use
Literal?β Restricts values to predefined choices
β Improves code readability and maintainability
β Helps static type checkers detect invalid values
β Commonly used in APIs, configuration options, and application settings
---
Challenge:
Create a function named:
set_language()
The function should accept only these values:
"English"
"French"
"Spanish"
using `Literal
.
Then call the function with:
``python"English"
`and print the selected language.
Python coding
π Python Tip #66: The typing.Literal Type The Literal type from Python's typing module allows you to restrict a variable or function parameter to specific, predefined values. This improves type safety and makes your code easier to understand. --- Importingβ¦
π‘ Python Tip #67: The
The
While Python does not enforce this at runtime, static type checkers can detect violations.
---
Importing
---
Declaring a Constant
Output:
The value of
---
Using
Output:
Attempting to reassign it:
A static type checker will report this as an error.
---
Using
Output:
The `VERSION
from typing import Final
class Animal:
@Final
def speak(self):
print("Animal sound")
python
APP_NAME
python
"Python Learning Hub"
3. Print the constant.
4. Try to assign a new value to it and observe the warning from your static type checker.
typing.Final TypeThe
Final type from Python's typing module indicates that a variable, constant, or method should not be reassigned or overridden.While Python does not enforce this at runtime, static type checkers can detect violations.
---
Importing
Finalfrom typing import Final
---
Declaring a Constant
from typing import Final
PI: Final = 3.14159
print(PI)
Output:
3.14159
The value of
PI is intended to remain unchanged.---
Using
Final with Variablesfrom typing import Final
MAX_USERS: Final = 100
print(MAX_USERS)
Output:
100
Attempting to reassign it:
MAX_USERS = 200
A static type checker will report this as an error.
---
Using
Final in Classesfrom typing import Final
class Configuration:
VERSION: Final = "1.0.0"
print(Configuration.VERSION)
Output:
1.0.0
The `VERSION
constant is intended to remain fixed.
---
Using Final for Methods
``pythonfrom typing import Final
class Animal:
@Final
def speak(self):
print("Animal sound")
A subclass should not override the `speak()` method.
---
Why use `Final`?
β Clearly marks constants and fixed values
β Helps prevent accidental reassignment
β Improves code readability and maintainability
β Commonly used for configuration values, constants, and methods that should not be overridden
---
Challenge:
Create a program that:
1. Declares a constant named:
python
APP_NAME
using `Final`.
2. Assign it the value:
python
"Python Learning Hub"
`3. Print the constant.
4. Try to assign a new value to it and observe the warning from your static type checker.
Python coding
π‘ Python Tip #67: The typing.Final Type The Final type from Python's typing module indicates that a variable, constant, or method should not be reassigned or overridden. While Python does not enforce this at runtime, static type checkers can detect violations.β¦
π Python Tip #68: The
The
This metadata can be used by frameworks, libraries, documentation tools, or static analysis tools without changing the underlying type.
---
Importing
---
Basic Example
Output:
The variable is still an
---
Using
Output:
---
Using Multiple Metadata Values
You can attach more than one piece of metadata.
Output:
---
Combining with Other Type Hints
Output:
The list contains integers, while the metadata describes what those integers represent.
---
Why use
β Adds metadata without changing the original type
β Improves documentation and code readability
β Useful for validation frameworks and APIs
β Commonly used in FastAPI, Pydantic, and modern Python applications
---
Challenge:
Create a function named:
The function should accept:
Use `Annotated
username = "Yehya"
age = 16
typing.Annotated TypeThe
Annotated type from Python's typing module allows you to attach additional metadata to type hints.This metadata can be used by frameworks, libraries, documentation tools, or static analysis tools without changing the underlying type.
---
Importing
Annotatedfrom typing import Annotated
---
Basic Example
from typing import Annotated
age: Annotated[int, "Age must be between 0 and 120"] = 16
print(age)
Output:
16
The variable is still an
int, but it now includes extra descriptive metadata.---
Using
Annotated in Functionsfrom typing import Annotated
def greet(
name: Annotated[str, "User's full name"]
):
print(f"Hello, {name}!")
greet("Yehya")
Output:
Hello, Yehya!
---
Using Multiple Metadata Values
You can attach more than one piece of metadata.
from typing import Annotated
temperature: Annotated[
float,
"Measured in Celsius",
"Range: -50 to 100"
] = 26.5
print(temperature)
Output:
26.5
---
Combining with Other Type Hints
from typing import Annotated
scores: list[
Annotated[int, "Exam score"]
] = [85, 92, 78]
print(scores)
Output:
[85, 92, 78]
The list contains integers, while the metadata describes what those integers represent.
---
Why use
Annotated?β Adds metadata without changing the original type
β Improves documentation and code readability
β Useful for validation frameworks and APIs
β Commonly used in FastAPI, Pydantic, and modern Python applications
---
Challenge:
Create a function named:
register_user()
The function should accept:
username
age
Use `Annotated
to add the following descriptions:
- Username of the new user
- User's age in years
Then call the function with:
``pythonusername = "Yehya"
age = 16
`
Python coding
π Python Tip #68: The typing.Annotated Type The Annotated type from Python's typing module allows you to attach additional metadata to type hints. This metadata can be used by frameworks, libraries, documentation tools, or static analysis tools without changingβ¦
π Python Tip #69: The
The
It helps prevent mixing different values that share the same underlying type, such as
---
Importing
---
Creating a New Type
Output:
Although
---
Using
Output:
This makes the function's purpose clearer and helps prevent passing the wrong type.
---
Creating Multiple New Types
Output:
Even though both are based on
---
Why use
β Creates meaningful custom types
β Prevents mixing logically different values
β Improves code readability and type safety
β Commonly used in APIs, databases, and large Python applications
---
Challenge:
Create two new types:
Both should be based on
Then:
1. Create one value for each type.
2. Print both values.
3. Write a function that accepts only a
typing.NewType FunctionThe
NewType function from Python's typing module creates a distinct type based on an existing type.It helps prevent mixing different values that share the same underlying type, such as
int or str.---
Importing
NewTypefrom typing import NewType
---
Creating a New Type
from typing import NewType
UserId = NewType("UserId", int)
user_id = UserId(101)
print(user_id)
Output:
101
Although
UserId behaves like an int at runtime, static type checkers treat it as a separate type.---
Using
NewType in Functionsfrom typing import NewType
UserId = NewType("UserId", int)
def get_user(user_id: UserId):
print(f"User ID: {user_id}")
get_user(UserId(15))
Output:
User ID: 15
This makes the function's purpose clearer and helps prevent passing the wrong type.
---
Creating Multiple New Types
from typing import NewType
UserId = NewType("UserId", int)
ProductId = NewType("ProductId", int)
user = UserId(1)
product = ProductId(1)
print(user)
print(product)
Output:
1
1
Even though both are based on
int, type checkers recognize them as different types.---
Why use
NewType?β Creates meaningful custom types
β Prevents mixing logically different values
β Improves code readability and type safety
β Commonly used in APIs, databases, and large Python applications
---
Challenge:
Create two new types:
StudentId
TeacherId
Both should be based on
int.Then:
1. Create one value for each type.
2. Print both values.
3. Write a function that accepts only a
StudentId and prints it.`
Python coding
π Python Tip #69: The typing.NewType Function The NewType function from Python's typing module creates a distinct type based on an existing type. It helps prevent mixing different values that share the same underlying type, such as int or str. --- Importingβ¦
π Python Tip #70: The
The
It is especially useful when working with functions such as
---
Importing
---
Basic Example
Output:
These functions are equivalent to:
---
Using
Output:
---
Using
Output:
---
Sorting in Reverse
Output:
---
Why use
β Provides functions for common operators
β Works perfectly with functional programming tools
β Makes sorting complex data easier
β Commonly used with
---
Challenge:
Given:
Use:
```python
operator.itemgetter()
text
Sara
Mariam
Ali
John
operator ModuleThe
operator module provides functions that correspond to Python's built-in operators.It is especially useful when working with functions such as
map(), filter(), and sorted().---
Importing
operatorimport operator
---
Basic Example
import operator
print(operator.add(10, 5))
print(operator.sub(10, 5))
print(operator.mul(10, 5))
print(operator.truediv(10, 5))
Output:
15
5
50
2.0
These functions are equivalent to:
10 + 5
10 - 5
10 * 5
10 / 5
---
Using
operator with map()import operator
numbers = [1, 2, 3, 4]
result = list(map(operator.mul, numbers, [2, 2, 2, 2]))
print(result)
Output:
[2, 4, 6, 8]
---
Using
operator.itemgetter()itemgetter() is useful for sorting lists of dictionaries or tuples.from operator import itemgetter
students = [
{"name": "Ali", "score": 85},
{"name": "Sara", "score": 95},
{"name": "John", "score": 78}
]
students.sort(key=itemgetter("score"))
print(students)
Output:
[
{'name': 'John', 'score': 78},
{'name': 'Ali', 'score': 85},
{'name': 'Sara', 'score': 95}
]
---
Sorting in Reverse
from operator import itemgetter
students.sort(
key=itemgetter("score"),
reverse=True
)
print(students)
Output:
[
{'name': 'Sara', 'score': 95},
{'name': 'Ali', 'score': 85},
{'name': 'John', 'score': 78}
]
---
Why use
operator?β Provides functions for common operators
β Works perfectly with functional programming tools
β Makes sorting complex data easier
β Commonly used with
map(), sorted(), filter(), and data processing---
Challenge:
Given:
students = [
{"name": "Ali", "score": 82},
{"name": "Sara", "score": 96},
{"name": "John", "score": 74},
{"name": "Mariam", "score": 89}
]
Use:
```python
operator.itemgetter()
to sort the students by their score from highest to lowest.
Expected order:
text
Sara
Mariam
Ali
John
`
Python coding
π Python Tip #70: The operator Module The operator module provides functions that correspond to Python's built-in operators. It is especially useful when working with functions such as map(), filter(), and sorted(). --- Importing operator import operatorβ¦
π Python Tip #71: The
The
It is especially useful when sorting custom objects.
---
Importing
---
Basic Example
Output:
---
Sorting Objects
Output:
---
Sorting in Reverse
Output:
---
Getting Multiple Attributes
Output:
---
Why use
β Retrieves object attributes efficiently
β Makes sorting custom objects simple
β Works well with
β Useful in object-oriented programming and data processing
---
Challenge:
Create a
Create at least four products.
Then use:
to sort them from cheapest to most expensive.
operator.attrgetter() FunctionThe
attrgetter() function from Python's operator module lets you retrieve attributes from objects.It is especially useful when sorting custom objects.
---
Importing
attrgetterfrom operator import attrgetter
---
Basic Example
from operator import attrgetter
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
student = Student("Yehya", 95)
print(attrgetter("name")(student))
print(attrgetter("score")(student))
Output:
Yehya
95
---
Sorting Objects
from operator import attrgetter
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
students = [
Student("Ali", 82),
Student("Sara", 96),
Student("John", 74),
Student("Mariam", 89)
]
students.sort(key=attrgetter("score"))
for student in students:
print(student.name, student.score)
Output:
John 74
Ali 82
Mariam 89
Sara 96
---
Sorting in Reverse
students.sort(
key=attrgetter("score"),
reverse=True
)
for student in students:
print(student.name, student.score)
Output:
Sara 96
Mariam 89
Ali 82
John 74
---
Getting Multiple Attributes
from operator import attrgetter
get_info = attrgetter("name", "score")
print(get_info(student))
Output:
('Yehya', 95)---
Why use
attrgetter()?β Retrieves object attributes efficiently
β Makes sorting custom objects simple
β Works well with
sorted() and .sort() β Useful in object-oriented programming and data processing
---
Challenge:
Create a
Product class with:name
price
Create at least four products.
Then use:
attrgetter("price")to sort them from cheapest to most expensive.
Python coding
π Python Tip #71: The operator.attrgetter() Function The attrgetter() function from Python's operator module lets you retrieve attributes from objects. It is especially useful when sorting custom objects. --- Importing attrgetter from operator importβ¦
π Python Tip #72: The
The
It is useful when working with functions like
---
Importing
---
Basic Example
Output:
This is similar to:
---
Using
Output:
---
Passing Arguments to a Method
Output:
---
Using
Output:
---
Why use
β Calls methods dynamically
β Works well with
β Can pass arguments to methods
β Useful in functional programming and data processing
---
Challenge:
Given:
Use:
```python
methodcaller()
python
['PYTHON', 'PROGRAMMING', 'DEVELOPER']
operator.methodcaller() FunctionThe
methodcaller() function from Python's operator module creates a callable that calls a specific method on an object.It is useful when working with functions like
map().---
Importing
methodcallerfrom operator import methodcaller
---
Basic Example
from operator import methodcaller
upper = methodcaller("upper")
print(upper("python"))
Output:
PYTHON
This is similar to:
"python".upper()
---
Using
methodcaller() with map()from operator import methodcaller
words = ["python", "java", "c++"]
result = list(map(methodcaller("upper"), words))
print(result)
Output:
['PYTHON', 'JAVA', 'C++']
---
Passing Arguments to a Method
methodcaller() can also pass arguments to the method.from operator import methodcaller
words = ["python", "programming", "coding"]
result = list(
map(methodcaller("replace", "o", "0"), words)
)
print(result)
Output:
['pyth0n', 'pr0gramming', 'c0ding']
---
Using
methodcaller() with Custom Classesfrom operator import methodcaller
class Student:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, {self.name}!"
students = [
Student("Ali"),
Student("Sara"),
Student("John")
]
greet = methodcaller("greet")
for message in map(greet, students):
print(message)
Output:
Hello, Ali!
Hello, Sara!
Hello, John!
---
Why use
methodcaller()?β Calls methods dynamically
β Works well with
map() β Can pass arguments to methods
β Useful in functional programming and data processing
---
Challenge:
Given:
words = [
"python",
"programming",
"developer"
]
Use:
```python
methodcaller()
with `map()` to convert every word to uppercase.
Expected Output:
python
['PYTHON', 'PROGRAMMING', 'DEVELOPER']
`
Python coding
π Python Tip #72: The operator.methodcaller() Function The methodcaller() function from Python's operator module creates a callable that calls a specific method on an object. It is useful when working with functions like map(). --- Importing methodcallerβ¦
π Python Tip #73: The
The
It can help you create combinations, permutations, repeated values, and efficient loops.
---
Importing
---
Creating Combinations
Output:
The order does not matter in combinations.
---
Creating Permutations
Output:
Notice that
---
Repeating Values with
Output:
---
Why use
β Provides efficient iterator-based tools
β Useful for combinations and permutations
β Helps avoid writing complex loops manually
β Commonly used in algorithms, data processing, and mathematical problems
---
Challenge:
Given:
Use:
```python
combinations()
python
('Ali', 'Sara')
('Ali', 'John')
('Ali', 'Mariam')
('Sara', 'John')
('Sara', 'Mariam')
('John', 'Mariam')
itertools ModuleThe
itertools module provides powerful tools for working with iterators.It can help you create combinations, permutations, repeated values, and efficient loops.
---
Importing
itertoolsimport itertools
---
Creating Combinations
combinations() generates all possible combinations of a specific length.from itertools import combinations
numbers = [1, 2, 3, 4]
result = list(combinations(numbers, 2))
print(result)
Output:
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
The order does not matter in combinations.
---
Creating Permutations
permutations() generates arrangements where order matters.from itertools import permutations
numbers = [1, 2, 3]
result = list(permutations(numbers, 2))
print(result)
Output:
[
(1, 2),
(1, 3),
(2, 1),
(2, 3),
(3, 1),
(3, 2)
]
Notice that
(1, 2) and (2, 1) are different.---
Repeating Values with
repeat()from itertools import repeat
for value in repeat("Python", 3):
print(value)
Output:
Python
Python
Python
---
Why use
itertools?β Provides efficient iterator-based tools
β Useful for combinations and permutations
β Helps avoid writing complex loops manually
β Commonly used in algorithms, data processing, and mathematical problems
---
Challenge:
Given:
students = ["Ali", "Sara", "John", "Mariam"]
Use:
```python
combinations()
to generate every possible **pair of students**.
Expected Output:
python
('Ali', 'Sara')
('Ali', 'John')
('Ali', 'Mariam')
('Sara', 'John')
('Sara', 'Mariam')
('John', 'Mariam')
`
Python coding
π Python Tip #73: The itertools Module The itertools module provides powerful tools for working with iterators. It can help you create combinations, permutations, repeated values, and efficient loops. --- Importing itertools import itertools --- Creatingβ¦
π Python Tip #74:
The
It's useful when you want to loop through several lists without creating a new combined list.
---
Importing
---
Basic Example
Output:
---
Combining Lists
You can also convert the result into a list:
Output:
---
Why use
β Combines multiple iterables efficiently
β Avoids unnecessary nested loops
β Doesn't create a new combined list unless you explicitly convert it
β Useful for data processing and working with large collections
---
Challenge:
Given:
Use:
```python
chain()
text
Ali
Sara
John
Mariam
Yusuf
Aisha
itertools.chain()The
chain() function from the itertools module lets you combine multiple iterables into one continuous iterator.It's useful when you want to loop through several lists without creating a new combined list.
---
Importing
chainfrom itertools import chain
---
Basic Example
from itertools import chain
numbers1 = [1, 2, 3]
numbers2 = [4, 5, 6]
for number in chain(numbers1, numbers2):
print(number)
Output:
1
2
3
4
5
6
---
Combining Lists
You can also convert the result into a list:
from itertools import chain
list1 = ["A", "B"]
list2 = ["C", "D"]
list3 = ["E", "F"]
result = list(chain(list1, list2, list3))
print(result)
Output:
['A', 'B', 'C', 'D', 'E', 'F']
---
Why use
chain()?β Combines multiple iterables efficiently
β Avoids unnecessary nested loops
β Doesn't create a new combined list unless you explicitly convert it
β Useful for data processing and working with large collections
---
Challenge:
Given:
group1 = ["Ali", "Sara"]
group2 = ["John", "Mariam"]
group3 = ["Yusuf", "Aisha"]
Use:
```python
chain()
to loop through all six students and print their names one by one.
Expected Output:
text
Ali
Sara
John
Mariam
Yusuf
Aisha
`
Python coding
π Python Tip #74: itertools.chain() The chain() function from the itertools module lets you combine multiple iterables into one continuous iterator. It's useful when you want to loop through several lists without creating a new combined list. --- Importingβ¦
π Python Tip #75:
The
It's especially useful when working with large datasets, generators, and streams.
---
Importing
---
Basic Example
Output:
This takes the first 5 items.
---
Using Start and Stop
Output:
The syntax is similar to:
---
Using a Step
Output:
The third argument specifies the step.
---
Working with a Generator
Output:
Only the required values are consumed from the generator.
---
Why use
β Efficiently processes part of an iterable
β Doesn't require slicing support
β Works with generators and iterators
β Useful for large datasets and streams
---
Challenge:
Create a generator that produces numbers from
Use:
to extract only the numbers from position
Expected Output:
itertools.islice()The
islice() function from Python's itertools module allows you to select a specific portion of an iterable without creating the entire sequence in memory.It's especially useful when working with large datasets, generators, and streams.
---
Importing
islicefrom itertools import islice
---
Basic Example
from itertools import islice
numbers = range(10)
result = list(islice(numbers, 5))
print(result)
Output:
[0, 1, 2, 3, 4]
This takes the first 5 items.
---
Using Start and Stop
from itertools import islice
numbers = range(10)
result = list(islice(numbers, 2, 7))
print(result)
Output:
[2, 3, 4, 5, 6]
The syntax is similar to:
numbers[2:7]
---
Using a Step
from itertools import islice
numbers = range(20)
result = list(islice(numbers, 0, 20, 3))
print(result)
Output:
[0, 3, 6, 9, 12, 15, 18]
The third argument specifies the step.
---
Working with a Generator
from itertools import islice
def numbers():
for i in range(1000000):
yield i
result = list(islice(numbers(), 10))
print(result)
Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Only the required values are consumed from the generator.
---
Why use
islice()?β Efficiently processes part of an iterable
β Doesn't require slicing support
β Works with generators and iterators
β Useful for large datasets and streams
---
Challenge:
Create a generator that produces numbers from
1 to 1000.Use:
islice()
to extract only the numbers from position
50 through 59.Expected Output:
[51, 52, 53, 54, 55, 56, 57, 58, 59, 60]
β€2
Python coding
π Python Tip #75: itertools.islice() The islice() function from Python's itertools module allows you to select a specific portion of an iterable without creating the entire sequence in memory. It's especially useful when working with large datasets, generatorsβ¦
π Python Tip #76: Regular Expressions with
Python's
Regex is extremely useful for text processing, validation, and searching patterns.
---
Importing
---
Searching for a Pattern
Output:
---
Finding All Matches
Use
Output:
---
Extracting Numbers
Output:
Here, `\d+
import re
text = "Python is difficult."
result = re.sub(r"difficult", "fun", text)
print(result)
text
Python is fun.
python
import re
email = "student@example.com"
pattern = r"^[\w.-]+@[\w.-]+\.\w+$"
if re.fullmatch(pattern, email):
print("Valid email")
else:
print("Invalid email")
text
Valid email
text
\d β digit
\w β letter, digit, or underscore
\s β whitespace
+ β one or more
* β zero or more
? β zero or one
^ β beginning of string
$ β end of string
. β any character
python
text = "Contact us at 123-456-7890 or 987-654-3210."
python
['123-456-7890', '987-654-3210']
rePython's
re module lets you search, match, extract, and replace text using regular expressions (regex).Regex is extremely useful for text processing, validation, and searching patterns.
---
Importing
reimport re
---
Searching for a Pattern
import re
text = "I am learning Python."
match = re.search(r"Python", text)
if match:
print("Python was found!")
Output:
Python was found!
---
Finding All Matches
Use
findall() to get every occurrence of a pattern.import re
text = "Python is powerful. Python is popular."
matches = re.findall(r"Python", text)
print(matches)
Output:
['Python', 'Python']
---
Extracting Numbers
import re
text = "I have 25 books and 3 notebooks."
numbers = re.findall(r"\d+", text)
print(numbers)
Output:
['25', '3']
Here, `\d+
means "one or more digits."
---
Replacing Text
Use sub() to replace matching text.
``pythonimport re
text = "Python is difficult."
result = re.sub(r"difficult", "fun", text)
print(result)
Output:
text
Python is fun.
---
Simple Email Pattern
python
import re
email = "student@example.com"
pattern = r"^[\w.-]+@[\w.-]+\.\w+$"
if re.fullmatch(pattern, email):
print("Valid email")
else:
print("Invalid email")
Output:
text
Valid email
---
Useful Regex Patterns
text
\d β digit
\w β letter, digit, or underscore
\s β whitespace
+ β one or more
* β zero or more
? β zero or one
^ β beginning of string
$ β end of string
. β any character
---
Why use `re`?
β Search text using patterns
β Extract useful information
β Validate input formats
β Replace matching text
β Useful in automation, data processing, web development, and text analysis
---
Challenge:
Given:
python
text = "Contact us at 123-456-7890 or 987-654-3210."
Use `re.findall()` to extract all phone numbers.
Expected Output:
python
['123-456-7890', '987-654-3210']
`
Python coding
π Python Tip #76: Regular Expressions with re Python's re module lets you search, match, extract, and replace text using regular expressions (regex). Regex is extremely useful for text processing, validation, and searching patterns. --- Importing re importβ¦
π Python Tip #77:
The
It is especially useful when you want to combine generators without writing an extra loop.
---
Basic Example:
Output:
This is equivalent to:
---
Combining Generators:
Output:
Instead of manually looping through each generator,
---
Using Multiple Iterables:
Output:
---
Why use
β Makes generator code shorter
β Combines multiple generators easily
β Avoids unnecessary nested loops
β Works efficiently with iterators
β Useful for data pipelines and recursive generators
---
Challenge:
Create three generators:
Make `foods()
['Apple', 'Banana', 'Carrot', 'Potato']
yield fromThe
yield from statement lets a generator delegate part of its work to another iterable or generator.It is especially useful when you want to combine generators without writing an extra loop.
---
Basic Example:
def numbers():
yield from [1, 2, 3, 4]
for number in numbers():
print(number)
Output:
1
2
3
4
This is equivalent to:
def numbers():
for number in [1, 2, 3, 4]:
yield number
---
Combining Generators:
def first():
yield 1
yield 2
yield 3
def second():
yield 4
yield 5
yield 6
def all_numbers():
yield from first()
yield from second()
print(list(all_numbers()))
Output:
[1, 2, 3, 4, 5, 6]
Instead of manually looping through each generator,
yield from delegates the iteration automatically.---
Using Multiple Iterables:
def combined():
yield from ["Python", "Java"]
yield from ["C++", "JavaScript"]
print(list(combined()))
Output:
['Python', 'Java', 'C++', 'JavaScript']
---
Why use
yield from?β Makes generator code shorter
β Combines multiple generators easily
β Avoids unnecessary nested loops
β Works efficiently with iterators
β Useful for data pipelines and recursive generators
---
Challenge:
Create three generators:
def fruits():
yield "Apple"
yield "Banana"
def vegetables():
yield "Carrot"
yield "Potato"
def foods():
# Use yield from here
pass
Make `foods()
produce all four items.
Expected Output:
``python['Apple', 'Banana', 'Carrot', 'Potato']
`
Python coding
π Python Tip #77: yield from The yield from statement lets a generator delegate part of its work to another iterable or generator. It is especially useful when you want to combine generators without writing an extra loop. --- Basic Example: def numbers():β¦
π Python Tip #78:
The
It's useful for organizing and analyzing sequences of data.
---
Importing
---
Basic Example
Output:
---
Important:
Output:
It does not automatically combine all identical values.
---
Grouping Objects by a Key
Output:
---
Sorting Before Grouping
If equal values are not next to each other, sort the data first.
Output:
---
Why use
β Groups related consecutive data
β Works efficiently with iterators
β Useful for data processing and organization
β Can group complex objects using a key function
---
Challenge:
Given:
Use `groupby()
Print each class and the students belonging to it.
itertools.groupby()The
groupby() function from Python's itertools module groups consecutive elements that have the same key.It's useful for organizing and analyzing sequences of 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]
---
Important:
groupby() Groups Consecutive Valuesfrom itertools import groupby
numbers = [1, 2, 1, 2, 1]
for key, group in groupby(numbers):
print(key, list(group))
Output:
1 [1]
2 [2]
1 [1]
2 [2]
1 [1]
It does not automatically combine all identical values.
---
Grouping Objects by a Key
from itertools import groupby
students = [
{"name": "Ali", "grade": "A"},
{"name": "Sara", "grade": "A"},
{"name": "John", "grade": "B"},
{"name": "Mariam", "grade": "B"}
]
for grade, group in groupby(students, key=lambda student: student["grade"]):
print(grade, list(group))
Output:
A [{'name': 'Ali', 'grade': 'A'}, {'name': 'Sara', 'grade': 'A'}]
B [{'name': 'John', 'grade': 'B'}, {'name': 'Mariam', 'grade': 'B'}]---
Sorting Before Grouping
If equal values are not next to each other, sort the data first.
from itertools import groupby
numbers = [2, 1, 2, 3, 1, 3, 2]
numbers.sort()
for key, group in groupby(numbers):
print(key, list(group))
Output:
1 [1, 1]
2 [2, 2, 2]
3 [3, 3]
---
Why use
groupby()?β Groups related consecutive data
β Works efficiently with iterators
β Useful for data processing and organization
β Can group complex objects using a key function
---
Challenge:
Given:
students = [
{"name": "Ali", "class": "A"},
{"name": "Sara", "class": "A"},
{"name": "John", "class": "B"},
{"name": "Mariam", "class": "B"},
{"name": "Yusuf", "class": "C"}
]
Use `groupby()
to group the students by their "class"`.Print each class and the students belonging to it.
Python coding
π Python Tip #78: itertools.groupby() The groupby() function from Python's itertools module groups consecutive elements that have the same key. It's useful for organizing and analyzing sequences of data. --- Importing groupby from itertools import groupbyβ¦
π Python Tip #79:
The
This is useful when you want to reuse a function with certain values fixed.
---
Importing
---
Basic Example
Output:
Here,
So:
is effectively:
---
Creating Multiple Specialized Functions
Output:
---
Using
Output:
---
Why use
β Reuses existing functions
β Pre-fills function arguments
β Creates specialized versions of functions
β Useful with callbacks,
---
Challenge:
Create a function:
Then use
where the tax is fixed at:
Test it with:
Expected output:
functools.partial()The
partial() function from Python's functools module lets you create a new function with some arguments already filled in.This is useful when you want to reuse a function with certain values fixed.
---
Importing
partialfrom functools import partial
---
Basic Example
from functools import partial
def multiply(a, b):
return a * b
double = partial(multiply, 2)
print(double(5))
print(double(10))
Output:
10
20
Here,
2 is automatically supplied as the first argument.So:
double(5)
is effectively:
multiply(2, 5)
---
Creating Multiple Specialized Functions
from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5))
print(cube(5))
Output:
25
125
---
Using
partial() with map()from functools import partial
def add(number, amount):
return number + amount
add_10 = partial(add, amount=10)
numbers = [1, 2, 3, 4]
result = list(map(add_10, numbers))
print(result)
Output:
[11, 12, 13, 14]
---
Why use
partial()?β Reuses existing functions
β Pre-fills function arguments
β Creates specialized versions of functions
β Useful with callbacks,
map(), event handlers, and APIs---
Challenge:
Create a function:
def calculate(price, tax):
return price + (price * tax)
Then use
partial() to create:calculate_15_percent
where the tax is fixed at:
0.15
Test it with:
100
Expected output:
115.0
Python coding
π Python Tip #79: functools.partial() The partial() function from Python's functools module lets you create a new function with some arguments already filled in. This is useful when you want to reuse a function with certain values fixed. --- Importingβ¦
π Python Tip #80: The
Python's
This can be useful when building caches, object registries, and memory-sensitive applications.
---
Importing
import weakref
---
Basic Example
import weakref
class User:
def init(self, name):
self.name = name
user = User("Yehya")
reference = weakref.ref(user)
print(reference().name)
Output:
Yehya
---
What Happens When the Object Is Deleted?
import weakref
class User:
def init(self, name):
self.name = name
user = User("Yehya")
reference = weakref.ref(user)
print(reference())
del user
print(reference())
Output:
<main.User object at ...>
None
After
The weak reference doesn't keep it alive.
---
Using a Weak Reference Callback
You can run a function when the referenced object is about to be finalized.
import weakref
class User:
pass
def object_deleted(reference):
print("Object was deleted.")
user = User()
reference = weakref.ref(
user,
object_deleted
)
del user
Possible output:
Object was deleted.
---
Why use
β Helps avoid unnecessary memory retention
β Useful for caches and object registries
β Allows objects to be garbage-collected normally
β Useful in advanced Python applications and frameworks
---
Challenge:
Create a class named:
Product
Then:
1. Create a
2. Create a weak reference to it.
3. Print the object through the weak reference.
4. Delete the original object.
5. Check the weak reference again.
What do you expect it to return after the object is deleted?
weakref ModulePython's
weakref module lets you create references to objects without preventing those objects from being garbage-collected.This can be useful when building caches, object registries, and memory-sensitive applications.
---
Importing
weakrefimport weakref
---
Basic Example
import weakref
class User:
def init(self, name):
self.name = name
user = User("Yehya")
reference = weakref.ref(user)
print(reference().name)
Output:
Yehya
reference() gives you access to the original object while it still exists.---
What Happens When the Object Is Deleted?
import weakref
class User:
def init(self, name):
self.name = name
user = User("Yehya")
reference = weakref.ref(user)
print(reference())
del user
print(reference())
Output:
<main.User object at ...>
None
After
user is deleted and no strong references remain, the object can be garbage-collected.The weak reference doesn't keep it alive.
---
Using a Weak Reference Callback
You can run a function when the referenced object is about to be finalized.
import weakref
class User:
pass
def object_deleted(reference):
print("Object was deleted.")
user = User()
reference = weakref.ref(
user,
object_deleted
)
del user
Possible output:
Object was deleted.
---
Why use
weakref?β Helps avoid unnecessary memory retention
β Useful for caches and object registries
β Allows objects to be garbage-collected normally
β Useful in advanced Python applications and frameworks
---
Challenge:
Create a class named:
Product
Then:
1. Create a
Product object.2. Create a weak reference to it.
3. Print the object through the weak reference.
4. Delete the original object.
5. Check the weak reference again.
What do you expect it to return after the object is deleted?
Python coding
π Python Tip #80: The weakref Module Python's weakref module lets you create references to objects without preventing those objects from being garbage-collected. This can be useful when building caches, object registries, and memory-sensitive applications.β¦
π Python Tip #81:
Ever needed a list where you're constantly adding and removing items from both ends?
That's where
---
Importing
from collections import deque
---
Basic Example
from collections import deque
queue = deque(["Ali", "Sara", "John"])
queue.append("Mariam")
queue.appendleft("Yusuf")
print(queue)
Output:
deque(['Yusuf', 'Ali', 'Sara', 'John', 'Mariam'])
---
Removing Items
from collections import deque
queue = deque(["Ali", "Sara", "John"])
first = queue.popleft()
last = queue.pop()
print(first)
print(last)
print(queue)
Output:
Ali
John
deque(['Sara'])
---
Why not just use a normal list?
You can use:
numbers.pop(0)
But removing the first item from a large list can be slower because the remaining elements have to be shifted.
With
numbers.popleft()
Removing from the left is designed to be efficient.
---
Useful Methods
append(x) β add to the right
appendleft(x) β add to the left
pop() β remove from the right
popleft() β remove from the left
extend(items) β add multiple items to the right
rotate(n) β rotate the elements
---
Real Example: A Simple Queue
from collections import deque
tasks = deque()
tasks.append("Download file")
tasks.append("Process data")
tasks.append("Send report")
while tasks:
task = tasks.popleft()
print("Processing:", task)
Output:
Processing: Download file
Processing: Process data
Processing: Send report
This is a simple example of a FIFO queue:
First In β First Out
---
Why use
β Fast adding/removing from both ends
β Great for queues and task processing
β Useful for sliding windows and buffers
β Better suited than lists for frequent left-side operations
β Part of Python's standard library
---
Challenge:
Create a
["A", "B", "C"]
Then:
1. Add
2. Add
3. Remove the first item.
4. Remove the last item.
5. Print the final deque.
What do you get?
collections.dequeEver needed a list where you're constantly adding and removing items from both ends?
That's where
deque comes in.deque means "double-ended queue" and is designed for fast operations at both the beginning and the end of a sequence.---
Importing
dequefrom collections import deque
---
Basic Example
from collections import deque
queue = deque(["Ali", "Sara", "John"])
queue.append("Mariam")
queue.appendleft("Yusuf")
print(queue)
Output:
deque(['Yusuf', 'Ali', 'Sara', 'John', 'Mariam'])
---
Removing Items
from collections import deque
queue = deque(["Ali", "Sara", "John"])
first = queue.popleft()
last = queue.pop()
print(first)
print(last)
print(queue)
Output:
Ali
John
deque(['Sara'])
popleft() removes from the left side.pop() removes from the right side.---
Why not just use a normal list?
You can use:
numbers.pop(0)
But removing the first item from a large list can be slower because the remaining elements have to be shifted.
With
deque:numbers.popleft()
Removing from the left is designed to be efficient.
---
Useful Methods
append(x) β add to the right
appendleft(x) β add to the left
pop() β remove from the right
popleft() β remove from the left
extend(items) β add multiple items to the right
rotate(n) β rotate the elements
---
Real Example: A Simple Queue
from collections import deque
tasks = deque()
tasks.append("Download file")
tasks.append("Process data")
tasks.append("Send report")
while tasks:
task = tasks.popleft()
print("Processing:", task)
Output:
Processing: Download file
Processing: Process data
Processing: Send report
This is a simple example of a FIFO queue:
First In β First Out
---
Why use
deque?β Fast adding/removing from both ends
β Great for queues and task processing
β Useful for sliding windows and buffers
β Better suited than lists for frequent left-side operations
β Part of Python's standard library
---
Challenge:
Create a
deque containing:["A", "B", "C"]
Then:
1. Add
"D" to the right.2. Add
"Z" to the left.3. Remove the first item.
4. Remove the last item.
5. Print the final deque.
What do you get?
Python coding
π Python Tip #81: collections.deque Ever needed a list where you're constantly adding and removing items from both ends? That's where deque comes in. deque means "double-ended queue" and is designed for fast operations at both the beginning and the endβ¦
π Python Tip #82: The
Ever wanted to keep a list sorted without manually searching for where a new value should go?
Python's
It uses binary search to find the correct position in an already-sorted list.
---
Importing
import bisect
---
Finding Where to Insert
import bisect
numbers = [10, 20, 30, 40]
position = bisect.bisect(numbers, 25)
print(position)
Output:
2
The result
---
Inserting Automatically
You can use
import bisect
numbers = [10, 20, 30, 40]
bisect.insort(numbers, 25)
print(numbers)
Output:
[10, 20, 25, 30, 40]
No need to manually search for the correct position.
---
Another Example
import bisect
scores = [45, 60, 72, 85, 95]
bisect.insort(scores, 80)
print(scores)
Output:
[45, 60, 72, 80, 85, 95]
The list stays sorted automatically.
---
When duplicate values exist, these functions help decide where to insert.
import bisect
numbers = [10, 20, 20, 20, 30]
print(bisect.bisect_left(numbers, 20))
print(bisect.bisect_right(numbers, 20))
Output:
1
4
---
Why use
β Keeps sorted lists organized
β Uses binary search to find positions
β Useful for ranking and score systems
β Great for maintaining ordered data
β Built into Python's standard library
---
Challenge:
Start with:
numbers = [10, 20, 30, 40, 50]
Use
25
35
45
Then print the final list.
Expected result:
[10, 20, 25, 30, 35, 40, 45, 50]
bisect ModuleEver wanted to keep a list sorted without manually searching for where a new value should go?
Python's
bisect module can help.It uses binary search to find the correct position in an already-sorted list.
---
Importing
bisectimport bisect
---
Finding Where to Insert
import bisect
numbers = [10, 20, 30, 40]
position = bisect.bisect(numbers, 25)
print(position)
Output:
2
The result
2 means 25 should be inserted at index 2.---
Inserting Automatically
You can use
insort() to find the position AND insert the value.import bisect
numbers = [10, 20, 30, 40]
bisect.insort(numbers, 25)
print(numbers)
Output:
[10, 20, 25, 30, 40]
No need to manually search for the correct position.
---
Another Example
import bisect
scores = [45, 60, 72, 85, 95]
bisect.insort(scores, 80)
print(scores)
Output:
[45, 60, 72, 80, 85, 95]
The list stays sorted automatically.
---
bisect_left() vs bisect_right()When duplicate values exist, these functions help decide where to insert.
import bisect
numbers = [10, 20, 20, 20, 30]
print(bisect.bisect_left(numbers, 20))
print(bisect.bisect_right(numbers, 20))
Output:
1
4
bisect_left() gives the position before the existing 20s.bisect_right() gives the position after them.---
Why use
bisect?β Keeps sorted lists organized
β Uses binary search to find positions
β Useful for ranking and score systems
β Great for maintaining ordered data
β Built into Python's standard library
---
Challenge:
Start with:
numbers = [10, 20, 30, 40, 50]
Use
bisect.insort() to insert:25
35
45
Then print the final list.
Expected result:
[10, 20, 25, 30, 35, 40, 45, 50]
Python coding
π Python Tip #82: The bisect Module Ever wanted to keep a list sorted without manually searching for where a new value should go? Python's bisect module can help. It uses binary search to find the correct position in an already-sorted list. --- Importingβ¦
π Python Tip #83:
Need to quickly find the smallest or largest items in a collection?
Python's
It's especially useful when you repeatedly need the smallest or largest values without sorting the entire list every time.
---
Importing
import heapq
---
Creating a Min-Heap
A normal list can be turned into a heap using
import heapq
numbers = [7, 2, 9, 1, 5]
heapq.heapify(numbers)
print(numbers)
The smallest value is always at index
print(numbers[0])
Output:
1
---
Removing the Smallest Item
Use
import heapq
numbers = [7, 2, 9, 1, 5]
heapq.heapify(numbers)
smallest = heapq.heappop(numbers)
print(smallest)
print(numbers)
Output:
1
[2, 5, 9, 7]
The heap structure isn't necessarily completely sorted.
It only guarantees that the smallest item is at the front.
---
Adding an Item
Use
import heapq
numbers = [2, 5, 7]
heapq.heapify(numbers)
heapq.heappush(numbers, 1)
print(numbers)
Output:
[1, 2, 7, 5]
---
Getting the Smallest Items
You can use
import heapq
numbers = [15, 3, 27, 8, 12, 1]
result = heapq.nsmallest(3, numbers)
print(result)
Output:
[1, 3, 8]
You can also use
result = heapq.nlargest(3, numbers)
print(result)
Output:
[27, 15, 12]
---
Real Example: Priority Tasks
import heapq
tasks = []
heapq.heappush(tasks, (2, "Send email"))
heapq.heappush(tasks, (1, "Fix critical bug"))
heapq.heappush(tasks, (3, "Update documentation"))
while tasks:
priority, task = heapq.heappop(tasks)
print(priority, task)
Output:
1 Fix critical bug
2 Send email
3 Update documentation
The smaller priority number gets processed first.
---
Why use
β Useful for priority queues
β Efficiently handles the smallest items
β Can find the largest/smallest N values
β Useful in scheduling and algorithms
β Common in real-world data processing
---
Challenge:
Given:
numbers = [42, 7, 19, 3, 25, 11]
Use
1. Turn the list into a heap.
2. Remove the smallest value.
3. Add
4. Print the smallest 3 values.
Try solving it without using
heapqNeed to quickly find the smallest or largest items in a collection?
Python's
heapq module gives you a heap-based priority queue.It's especially useful when you repeatedly need the smallest or largest values without sorting the entire list every time.
---
Importing
heapqimport heapq
---
Creating a Min-Heap
A normal list can be turned into a heap using
heapify().import heapq
numbers = [7, 2, 9, 1, 5]
heapq.heapify(numbers)
print(numbers)
The smallest value is always at index
0.print(numbers[0])
Output:
1
---
Removing the Smallest Item
Use
heappop():import heapq
numbers = [7, 2, 9, 1, 5]
heapq.heapify(numbers)
smallest = heapq.heappop(numbers)
print(smallest)
print(numbers)
Output:
1
[2, 5, 9, 7]
The heap structure isn't necessarily completely sorted.
It only guarantees that the smallest item is at the front.
---
Adding an Item
Use
heappush():import heapq
numbers = [2, 5, 7]
heapq.heapify(numbers)
heapq.heappush(numbers, 1)
print(numbers)
Output:
[1, 2, 7, 5]
---
Getting the Smallest Items
You can use
nsmallest() when you only need a few of the smallest values.import heapq
numbers = [15, 3, 27, 8, 12, 1]
result = heapq.nsmallest(3, numbers)
print(result)
Output:
[1, 3, 8]
You can also use
nlargest():result = heapq.nlargest(3, numbers)
print(result)
Output:
[27, 15, 12]
---
Real Example: Priority Tasks
import heapq
tasks = []
heapq.heappush(tasks, (2, "Send email"))
heapq.heappush(tasks, (1, "Fix critical bug"))
heapq.heappush(tasks, (3, "Update documentation"))
while tasks:
priority, task = heapq.heappop(tasks)
print(priority, task)
Output:
1 Fix critical bug
2 Send email
3 Update documentation
The smaller priority number gets processed first.
---
Why use
heapq?β Useful for priority queues
β Efficiently handles the smallest items
β Can find the largest/smallest N values
β Useful in scheduling and algorithms
β Common in real-world data processing
---
Challenge:
Given:
numbers = [42, 7, 19, 3, 25, 11]
Use
heapq to:1. Turn the list into a heap.
2. Remove the smallest value.
3. Add
5.4. Print the smallest 3 values.
Try solving it without using
sorted().