Python coding
🚀 Python Tip #58: The tempfile Module The tempfile module allows you to create temporary files and directories that are automatically cleaned up when no longer needed. It is useful for testing, data processing, and handling temporary data. --- Importing…
💡 Python Tip #59: The
The
It makes it easy to copy, move, rename, and delete files and folders.
---
Importing
---
Copying a File
This creates a copy of
---
Moving or Renaming a File
If the destination is in another folder, the file is moved. If it's in the same folder with a different name, it is renamed.
---
Copying an Entire Directory
This copies the entire
---
Deleting a Directory
Warning:
---
Getting Disk Usage
Example Output:
---
Why use
✓ Copy, move, and rename files easily
✓ Copy or remove entire directories
✓ Check disk usage information
✓ Commonly used in backup tools, automation scripts, and file management applications
---
Challenge:
Create a program that:
1. Creates a copy of a file named:
2. Rename the copied file to:
3. Print a success message after each operation.
shutil ModuleThe
shutil module provides high-level file and directory operations.It makes it easy to copy, move, rename, and delete files and folders.
---
Importing
shutilimport shutil
---
Copying a File
import shutil
shutil.copy("source.txt", "backup.txt")
print("File copied successfully.")
This creates a copy of
source.txt named backup.txt.---
Moving or Renaming a File
import shutil
shutil.move("old_file.txt", "new_file.txt")
print("File moved or renamed.")
If the destination is in another folder, the file is moved. If it's in the same folder with a different name, it is renamed.
---
Copying an Entire Directory
import shutil
shutil.copytree("Project", "Project_Backup")
print("Directory copied.")
This copies the entire
Project folder, including all its files and subfolders.---
Deleting a Directory
import shutil
shutil.rmtree("Old_Project")
print("Directory deleted.")
Warning:
rmtree() permanently deletes the directory and everything inside it.---
Getting Disk Usage
import shutil
usage = shutil.disk_usage(".")
print(f"Total: {usage.total} bytes")
print(f"Used: {usage.used} bytes")
print(f"Free: {usage.free} bytes")
Example Output:
Total: 512110190592 bytes
Used: 301245964288 bytes
Free: 210864226304 bytes
---
Why use
shutil?✓ Copy, move, and rename files easily
✓ Copy or remove entire directories
✓ Check disk usage information
✓ Commonly used in backup tools, automation scripts, and file management applications
---
Challenge:
Create a program that:
1. Creates a copy of a file named:
notes.txt
2. Rename the copied file to:
notes_backup.txt
3. Print a success message after each operation.
Python coding
💡 Python Tip #59: The shutil Module The shutil module provides high-level file and directory operations. It makes it easy to copy, move, rename, and delete files and folders. --- Importing shutil import shutil --- Copying a File import shutil shut…
🚀 Python Tip #60: The
The
It helps you manage resources such as files, database connections, and locks safely and cleanly.
---
Importing
---
Creating a Custom Context Manager
Output:
The code before
---
Managing Resources
The file is automatically closed after leaving the
---
Ignoring Exceptions
Use
If the file doesn't exist, the program continues without raising an error.
---
Redirecting Output
You can temporarily redirect printed output.
The text is written to
---
Why use
✓ Create custom context managers easily
✓ Automatically manage resources
✓ Simplify exception handling
✓ Commonly used in file handling, testing, logging, and resource management
---
Challenge:
Create a custom context manager that:
1. Prints:
before entering the
2. Prints:
after leaving the
3. Inside the
contextlib ModuleThe
contextlib module provides utilities for working with context managers.It helps you manage resources such as files, database connections, and locks safely and cleanly.
---
Importing
contextmanagerfrom contextlib import contextmanager
---
Creating a Custom Context Manager
from contextlib import contextmanager
@contextmanager
def my_context():
print("Entering context...")
yield
print("Exiting context...")
with my_context():
print("Inside the block")
Output:
Entering context...
Inside the block
Exiting context...
The code before
yield runs when entering the block, and the code after yield runs when exiting it.---
Managing Resources
from contextlib import contextmanager
@contextmanager
def open_file(filename):
file = open(filename, "w")
try:
yield file
finally:
file.close()
with open_file("example.txt") as f:
f.write("Hello, Python!")
The file is automatically closed after leaving the
with block.---
Ignoring Exceptions
Use
suppress() to ignore specific exceptions.from contextlib import suppress
with suppress(FileNotFoundError):
open("missing_file.txt")
If the file doesn't exist, the program continues without raising an error.
---
Redirecting Output
You can temporarily redirect printed output.
from contextlib import redirect_stdout
with open("output.txt", "w") as file:
with redirect_stdout(file):
print("Hello, Python!")
The text is written to
output.txt instead of appearing in the terminal.---
Why use
contextlib?✓ Create custom context managers easily
✓ Automatically manage resources
✓ Simplify exception handling
✓ Commonly used in file handling, testing, logging, and resource management
---
Challenge:
Create a custom context manager that:
1. Prints:
Starting task...
before entering the
with block.2. Prints:
Task completed.
after leaving the
with block.3. Inside the
with block, print:Learning Python Context Managers!
Python coding pinned «Introduction to Programming with Python --- What is Python? Python is a popular programming language created by Guido van Rossum in 1991. It is known for: - Simplicity - Readability - Flexibility - Powerful libraries Python is beginner-friendly while…»
Python coding
🚀 Python Tip #60: The contextlib Module The contextlib module provides utilities for working with context managers. It helps you manage resources such as files, database connections, and locks safely and cleanly. --- Importing contextmanager from contextlib…
🐍 Python Tip #61: The
The
This is known as single dispatch or function overloading by type.
---
Importing
---
Basic Example
Output:
---
Registering Functions for Different Types
Output:
The correct function is selected automatically based on the argument type.
---
Supporting Multiple Types
Output:
---
Fallback Behavior
If no registered type matches, the original function is used.
Output:
---
Why use
✓ Organizes type-specific logic cleanly
✓ Avoids long
✓ Easy to extend by registering new types
✓ Useful in APIs, data processing, and reusable libraries
---
Challenge:
Create a function named:
using `@singledispatch
Each implementation should print a different message describing the received value.
functools.singledispatch DecoratorThe
singledispatch decorator from Python's functools module allows a function to behave differently depending on the type of its first argument.This is known as single dispatch or function overloading by type.
---
Importing
singledispatchfrom functools import singledispatch
---
Basic Example
from functools import singledispatch
@singledispatch
def show(value):
print("Unsupported type")
show(10)
Output:
Unsupported type
---
Registering Functions for Different Types
from functools import singledispatch
@singledispatch
def show(value):
print("Unsupported type")
@show.register
def _(value: int):
print(f"Integer: {value}")
@show.register
def _(value: str):
print(f"String: {value}")
show(100)
show("Python")
Output:
Integer: 100
String: Python
The correct function is selected automatically based on the argument type.
---
Supporting Multiple Types
from functools import singledispatch
@singledispatch
def describe(value):
print("Unknown type")
@describe.register
def _(value: list):
print(f"List with {len(value)} items")
@describe.register
def _(value: dict):
print(f"Dictionary with {len(value)} keys")
describe([1, 2, 3])
describe({"a": 1, "b": 2})
Output:
List with 3 items
Dictionary with 2 keys
---
Fallback Behavior
If no registered type matches, the original function is used.
describe(3.14)
Output:
Unknown type
---
Why use
singledispatch?✓ Organizes type-specific logic cleanly
✓ Avoids long
if isinstance() chains ✓ Easy to extend by registering new types
✓ Useful in APIs, data processing, and reusable libraries
---
Challenge:
Create a function named:
display()
using `@singledispatch
.
Register implementations for:
- int
- str
- tuple`Each implementation should print a different message describing the received value.
Python coding
🐍 Python Tip #61: The functools.singledispatch Decorator The singledispatch decorator from Python's functools module allows a function to behave differently depending on the type of its first argument. This is known as single dispatch or function overloading…
🚀 Python Tip #62: The
The
If the function is called again with the same arguments, the cached result is returned instantly instead of recalculating it.
This technique is called memoization.
---
Importing
---
Basic Example
Output:
Notice that
---
Speeding Up Recursive Functions
Without caching:
With caching:
The cached version is dramatically faster because previously computed values are reused.
---
Limiting Cache Size
Only the most recently used results are kept in the cache.
---
Clearing the Cache
This removes all cached results.
---
Why use
✓ Improves performance by avoiding repeated calculations
✓ Perfect for recursive algorithms like Fibonacci
✓ Easy to use with a single decorator
✓ Commonly used in dynamic programming, APIs, and computationally expensive functions
---
Challenge:
Create a recursive function that calculates the factorial of a number.
Then:
1. Decorate it with:
2. Calculate:
3. Call it a second time and observe that the cached result is returned instantly.
functools.lru_cache DecoratorThe
lru_cache decorator from Python's functools module stores the results of function calls.If the function is called again with the same arguments, the cached result is returned instantly instead of recalculating it.
This technique is called memoization.
---
Importing
lru_cachefrom functools import lru_cache
---
Basic Example
from functools import lru_cache
@lru_cache
def square(number):
print("Calculating...")
return number ** 2
print(square(5))
print(square(5))
Output:
Calculating...
25
25
Notice that
"Calculating..." is printed only once because the second call uses the cached result.---
Speeding Up Recursive Functions
Without caching:
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
With caching:
from 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(40))
The cached version is dramatically faster because previously computed values are reused.
---
Limiting Cache Size
from functools import lru_cache
@lru_cache(maxsize=5)
def cube(number):
print("Computing...")
return number ** 3
cube(2)
cube(3)
cube(2)
Only the most recently used results are kept in the cache.
---
Clearing the Cache
from functools import lru_cache
@lru_cache
def multiply(a, b):
return a * b
multiply(2, 3)
multiply.cache_clear()
This removes all cached results.
---
Why use
lru_cache?✓ Improves performance by avoiding repeated calculations
✓ Perfect for recursive algorithms like Fibonacci
✓ Easy to use with a single decorator
✓ Commonly used in dynamic programming, APIs, and computationally expensive functions
---
Challenge:
Create a recursive function that calculates the factorial of a number.
Then:
1. Decorate it with:
@lru_cache(maxsize=None)
2. Calculate:
factorial(10)
3. Call it a second time and observe that the cached result is returned instantly.
Python coding
🚀 Python Tip #62: The functools.lru_cache Decorator The lru_cache decorator from Python's functools module stores the results of function calls. If the function is called again with the same arguments, the cached result is returned instantly instead of recalculating…
💡 Python Tip #63: The
The
After the first access, the computed value is stored (cached), so future accesses return the cached result instead of recalculating it.
---
Importing
---
Basic Example
Output:
Notice that
---
Without
Output:
The calculation is performed every time the property is accessed.
---
Clearing the Cached Value
You can remove the cached value using
Output:
After deleting the cached value, it is calculated again the next time it is accessed.
---
Why use
✓ Improves performance for expensive calculations
✓ Computes a value only once per object
✓ Keeps code clean and readable
✓ Commonly used in data science, web frameworks, and applications with computationally expensive properties
---
Challenge:
Create a class named:
with the attributes:
Then:
1. Create a
2. Print the area twice.
3. Verify that the calculation occurs only once.
functools.cached_property DecoratorThe
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 instead of recalculating it.
---
Importing
cached_propertyfrom functools import cached_property
---
Basic Example
from functools import cached_property
class Circle:
def __init__(self, radius):
self.radius = radius
@cached_property
def area(self):
print("Calculating area...")
return 3.14159 * self.radius ** 2
circle = Circle(5)
print(circle.area)
print(circle.area)
Output:
Calculating area...
78.53975
78.53975
Notice that
"Calculating area..." is printed only once.---
Without
cached_propertyclass Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
print("Calculating area...")
return 3.14159 * self.radius ** 2
circle = Circle(5)
print(circle.area)
print(circle.area)
Output:
Calculating area...
78.53975
Calculating area...
78.53975
The calculation is performed every time the property is accessed.
---
Clearing the Cached Value
You can remove the cached value using
del.from functools import cached_property
class Square:
def __init__(self, side):
self.side = side
@cached_property
def area(self):
print("Calculating...")
return self.side ** 2
square = Square(4)
print(square.area)
del square.area
print(square.area)
Output:
Calculating...
16
Calculating...
16
After deleting the cached value, it is calculated again the next time it is accessed.
---
Why use
cached_property?✓ Improves performance for expensive calculations
✓ Computes a value only once per object
✓ Keeps code clean and readable
✓ Commonly used in data science, web frameworks, and applications with computationally expensive properties
---
Challenge:
Create a class named:
Rectangle
with the attributes:
width
height
Then:
1. Create a
cached_property named:area
2. Print the area twice.
3. Verify that the calculation occurs only once.
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
`