Python Cookbook
Python Cookbook
def http_status_code_message(status_code):
match status_code:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Internal Server Error"
case _:
return "Unknown Status Code"
print(http_status_code_message(200)) # OK
print(http_status_code_message(404)) # Not Found
print(http_status_code_message(123)) # Unknown Status
Code
print function
# Python 2 example
print "Hello, World!" # Hello, World!
print "The answer is", 42 # The answer is 42
# Using a trailing comma to avoid a newline at the end
print "Hello,",
print "World!" # Hello, World!
# Python 3 example
print("Hello, World!") # Hello, World!
print("The answer is", 42) # The answer is 42
# To avoid a newline at the end, use the end parameter
print("Hello,", end=" ")
print("World!") # Hello, World!
range function
# Python 2 example using range
numbers = range(1, 10)
print numbers # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Python 2 example using xrange
numbers = xrange(1, 10)
print numbers # xrange(1, 10)
print list(numbers) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Python 3 example using range
numbers = range(1, 10)
print(numbers) # range(1, 10)
print(list(numbers)) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Classes
In object-oriented programming, classes are fundamental
building blocks that define the blueprint for objects. A class
encapsulates data for the object and methods to manipulate
that data, promoting modularity and code reuse.
Check for reference equality
class MyClass:
def __init__(self, value):
self.value = value
# Create two instances of MyClass
obj1 = MyClass(10)
obj2 = MyClass(10)
obj3 = obj1
# Check for reference equality using id()
print(id(obj1) == id(obj2))
# False, different objects in memory
print(id(obj1) == id(obj3))
# True, same object in memory
Constructors:
Call of the own constructor
class Person:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
@classmethod
def from_full_name(cls, full_name, age):
first_name, last_name = full_name.split()
# Call the main constructor with first name and last
name extracted from full name
return cls(first_name, last_name, age)
def display_person(self):
print(f'Name: {self.first_name} {self.last_name}, Age:
{self.age}')
# Create an instance using the main constructor
person1 = Person("John", "Doe", 30)
person1.display_person()
# Output: Name: John Doe, Age: 30
# Create an instance using the alternative constructor
person2 = Person.from_full_name("Jane Smith", 25)
person2.display_person()
# Output: Name: Jane Smith, Age: 25
Call of the parent constructor
class Person:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
def display_person_info(self):
print(f'Name: {self.first_name} {self.last_name}, Age:
{self.age}')
class Employee(Person):
def __init__(self, first_name, last_name, age,
employee_id, position):
# Call the parent constructor to initialize first_name,
last_name, and age
super().__init__(first_name, last_name, age)
self.employee_id = employee_id
self.position = position
def display_employee_info(self):
# Call the parent class method to display basic info
super().display_person_info()
print(f'Employee ID: {self.employee_id}, Position:
{self.position}')
# Create an instance of Person
person = Person("John", "Doe", 45)
person.display_person_info() # Output: Name: John Doe,
Age: 45
# Create an instance of Employee
employee = Employee("Jane", "Smith", 30, "E123",
"Software Engineer")
employee.display_employee_info()
# Output:
# Name: Jane Smith, Age: 30
# Employee ID: E123, Position: Software Engineer
Default constructor
class Book:
def __init__(self, title="Unknown Title", author="Unknown
Author", year=0):
self.title = title
self.author = author
self.year = year
def display_info(self):
print(f'Title: {self.title}, Author: {self.author}, Year:
{self.year}')
# Create an instance using the default constructor
default_book = Book()
default_book.display_info()
# Output: Title: Unknown Title, Author: Unknown Author,
Year: 0
# Create an instance with custom values
custom_book = Book("1984", "George Orwell", 1949)
custom_book.display_info()
# Output: Title: 1984, Author: George Orwell, Year: 1949
Optional parameter values
class Car:
def __init__(self, make="Unknown Make",
model="Unknown Model", year=0, color="Unknown Color"):
self.make = make
self.model = model
self.year = year
self.color = color
def display_info(self):
print(f'Make: {self.make}, Model: {self.model}, Year:
{self.year}, Color: {self.color}')
# Create an instance using the default constructor (all
default values)
default_car = Car()
default_car.display_info() # Output: Make: Unknown Make,
Model: Unknown Model, Year: 0, Color: Unknown Color
# Create an instance with some custom values
custom_car1 = Car(make="Toyota", model="Corolla")
custom_car1.display_info()
# Output: Make: Toyota, Model: Corolla, Year: 0, Color:
Unknown Color
# Create an instance with all custom values
custom_car2 = Car(make="Honda", model="Civic",
year=2022, color="Red")
custom_car2.display_info()
# Output: Make: Honda, Model: Civic, Year: 2022, Color: Red
Replacement of the parent
constructor
class Person:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
def display_person_info(self):
print(f'Name: {self.first_name} {self.last_name}, Age:
{self.age}')
class Employee(Person):
def __init__(self, first_name, last_name, age,
employee_id, position):
# Call the parent constructor to initialize first_name,
last_name, and age
super().__init__(first_name, last_name, age)
# Initialize the additional attributes
self.employee_id = employee_id
self.position = position
def display_employee_info(self):
# Call the parent class method to display basic info
super().display_person_info()
print(f'Employee ID: {self.employee_id}, Position:
{self.position}')
# Create an instance of Person
person = Person("John", "Doe", 45)
person.display_person_info()
# Output: Name: John Doe, Age: 45
# Create an instance of Employee
employee = Employee("Jane", "Smith", 30, "E123",
"Software Engineer")
employee.display_employee_info()
# Output:
# Name: Jane Smith, Age: 30
# Employee ID: E123, Position: Software Engineer
With paramenters
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
# Creating an instance of Rectangle with specific
dimensions
rectangle1 = Rectangle(5, 3)
print("Area of rectangle1:", rectangle1.area())
# Output: Area of rectangle1: 15
# Creating another instance of Rectangle with different
dimensions
rectangle2 = Rectangle(7, 4)
print("Area of rectangle2:", rectangle2.area())
# Output: Area of rectangle2: 28
Without any paramenters
class MyClass:
def __init__(self):
print("This is the default constructor.")
def display(self):
print("Inside MyClass.")
# Creating an instance of MyClass
obj = MyClass()
obj.display()
Create a copy of the object
import copy
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def display_info(self):
print(f'Name: {self.name}, Age: {self.age}')
# Create an instance of Person
person1 = Person("Alice", 30)
person1.display_info()
# Output: Name: Alice, Age: 30
# Create a shallow copy of person1
person2 = copy.copy(person1)
person2.display_info()
# Output: Name: Alice, Age: 30
# Modify the copy
person2.name = "Bob"
person2.display_info()
# Output: Name: Bob, Age: 30
person1.display_info()
# Output: Name: Alice, Age: 30
# Create a deep copy of person1
person3 = copy.deepcopy(person1)
person3.display_info()
# Output: Name: Alice, Age: 30
Definition and initialization
# Definition
class SomeClass:
pass
# Initialization
someClass = SomeClass()
Descriptors
class AgeDescriptor:
def __init__(self):
self._age = None
def __get__(self, instance, owner):
print("Getting age")
return self._age
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError("Age must be an integer")
if value < 0:
raise ValueError("Age cannot be negative")
print("Setting age")
self._age = value
def __delete__(self, instance):
print("Deleting age")
self._age = None
class Person:
age = AgeDescriptor()
def __init__(self, name, age):
self.name = name
self.age = age
def display_info(self):
print(f'Name: {self.name}, Age: {self.age}')
# Create an instance of Person
person = Person("Alice", 30)
person.display_info()
# Output: Name: Alice, Age: 30
# Get the age
print(person.age)
# Output: Getting age, 30
# Set a new age
person.age = 35
# Output: Setting age
# Get the updated age
print(person.age)
# Output: Getting age, 35
# Delete the age
del person.age # Output: Deleting age
# Try to get the deleted age
print(person.age)
# Output: Getting age, None
class Circle:
def __init__(self):
self.radius = 0
@property
def area(self):
return math.pi * pow(self.radius, 2)
circle = Circle()
circle.radius = 2
# circle.area is 12.566370614359172
print(circle.area)
Read-Only properties: Stored
properties
class FilmList:
def __init__(self):
self.__count = 10
@property
def count(self):
return self.__count
filmList = FilmList()
count = filmList.count
print(count) # count is 10
Stored properties
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# Creating an instance of Person
person = Person("Alice", 30)
# Accessing stored properties
print("Name:", person.name) # Output: Name: Alice
print("Age:", person.age) # Output: Age: 30
# Modifying stored properties
person.name = "Bob"
person.age = 25
# Displaying modified properties
print("Modified Name:", person.name)
# Output: Modified Name: Bob
print("Modified Age:", person.age)
# Output: Modified Age: 25
Type properties
class Circle:
pi = 3.14159
def __init__(self, radius):
self.radius = radius
def calculate_area(self):
return Circle.pi * self.radius ** 2
# Creating instances of Circle
circle1 = Circle(5)
circle2 = Circle(10)
# Accessing the type property
print("Value of pi:", Circle.pi) # Output: Value of pi: 3.14159
# Calculating areas using type property
print("Area of circle 1:", circle1.calculate_area())
# Output: Area of circle 1: 78.53975
print("Area of circle 2:", circle2.calculate_area())
# Output: Area of circle 2: 314.159
Subscripts (indexer methods):
With generic parameter
class MyList:
def __init__(self):
self.data = {}
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
# Creating an instance of MyList
my_list = MyList()
# Using integer indices
my_list[0] = 'a'
my_list[1] = 'b'
print("Element at index 0:", my_list[0])
# Output: Element at index 0: a
print("Element at index 1:", my_list[1])
# Output: Element at index 1: b
# Using string keys
my_list['first'] = 10
my_list['second'] = 20
print("Element with key 'first':", my_list['first'])
# Output: Element with key 'first': 10
print("Element with key 'second':", my_list['second'])
# Output: Element with key 'second': 20
With multiple parameter
class Matrix:
def __init__(self, rows, columns):
self.rows = rows
self.columns = columns
self.data = [[0] * columns for _ in range(rows)]
def __getitem__(self, indices):
row, column = indices
return self.data[row][column]
def __setitem__(self, indices, value):
row, column = indices
self.data[row][column] = value
# Creating an instance of Matrix
matrix = Matrix(3, 3)
# Setting values using multiple indices
matrix[0, 0] = 1
matrix[1, 1] = 2
matrix[2, 2] = 3
# Getting values using multiple indices
print("Value at position (0, 0):", matrix[0, 0])
# Output: Value at position (0, 0): 1
print("Value at position (1, 1):", matrix[1, 1])
# Output: Value at position (1, 1): 2
print("Value at position (2, 2):", matrix[2, 2])
# Output: Value at position (2, 2): 3
With one parameter
class MyList:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
# Creating an instance of MyList
my_list = MyList([1, 2, 3, 4, 5])
# Accessing elements using single index
print("Element at index 0:", my_list[0])
# Output: Element at index 0: 1
print("Element at index 2:", my_list[2])
# Output: Element at index 2: 3
# Modifying elements using single index
my_list[1] = 10
my_list[3] = 20
print("Modified list:", my_list.data)
# Output: Modified list: [1, 10, 3, 20, 5]
Type member
class Employee:
# Class variable
company_name = "TechCorp"
employee_count = 0
def __init__(self, name, position):
self.name = name
self.position = position
Employee.employee_count += 1
# Class method
@classmethod
def set_company_name(cls, name):
cls.company_name = name
# Class method to get employee count
@classmethod
def get_employee_count(cls):
return cls.employee_count
# Accessing and modifying class variables
print("Company Name:", Employee.company_name)
# Output: Company Name: TechCorp
print("Initial Employee Count:",
Employee.employee_count)
# Output: Initial Employee Count: 0
# Creating instances of Employee
emp1 = Employee("Alice", "Developer")
emp2 = Employee("Bob", "Designer")
# Accessing class variable via instance
print("Company Name (via emp1):",
emp1.company_name)
# Output: Company Name (via emp1): TechCorp
print("Employee Count (via emp1):",
emp1.employee_count)
# Output: Employee Count (via emp1): 2
# Using class method to set company name
Employee.set_company_name("InnoTech")
print("Updated Company Name:",
Employee.company_name)
# Output: Updated Company Name: InnoTech
# Using class method to get employee count
print("Total Employees:",
Employee.get_employee_count())
# Output: Total Employees: 2
Control Flow
Control flow in programming determines the order in which
instructions are executed. It encompasses decision-making,
looping, and branching mechanisms that allow a program to
execute different code paths based on conditions. Key
constructs include conditional statements (if, else if, else)
for decision-making, switch statements for handling multiple
conditions, and loops (for, while, do...while) for repeating
code. Control flow also involves breaking out of loops with
"break" and skipping iterations with "continue". These
constructs are fundamental for creating dynamic and
responsive software that can adapt to various inputs and
situations.
if/else statements:
Complex conditions
X = 10
Y = 20
Z = 30
if Z > X and Z > Y:
if X < Y:
print("Z is the largest and X is smaller than Y.")
else:
print("Z is the largest but X is not smaller than Y.")
else:
print("Z is not the largest.")
# Output: Z is the largest and X is smaller than Y.
Is not valid example
# Invalid example
if latitud == 0 # SyntaxError: invalid syntax
location = "Equator"
Ternary operator
n = -42
classify = "positive" if n > 0 else "negative"
print(classify) # Output: negative
Valid example
import random
def get_latitude():
return random.randint(-90, 90)
latitude = get_latitude()
location = ""
if latitude == 0:
location = "Equator"
elif latitude == 90:
location = "North Pole"
elif latitude == -90:
location = "South Pole"
else:
location = "Not at the Equator or Pole"
print(f"latitude is {latitude}")
# Example output: latitude is -57
print(f"location is \"{location}\"")
# Example output: location is "Not at the Equator or Pole"
Match statements:
Different types of values
monitor_inch_size = 24
match monitor_inch_size:
case 15:
str = "too small"
case 16 | 17 | 18:
str = "good for the past decade"
case 19 | 20 | 21 | 22 | 23:
str = "for office work"
case 24 | 25 | 26 | 27:
str = "great choice"
case _:
str = ""
print(f'str is "{str}"')
# Output: str is "great choice"
Example with a tuple
message = ("error", 404, "Not Found")
match message:
case ("error", code, description):
result = f"Error {code}: {description}"
case ("warning", description):
result = f"Warning: {description}"
case ("info", description):
result = f"Info: {description}"
case ("success", code, description):
result = f"Success {code}: {description}"
case _:
result = "Unknown message type"
print(result) # Output: Error 404: Not Found
Match if conditions
numbers = [5, -2, 0, 10, -8]
for number in numbers:
match number:
case n if n > 0:
print(f"{n} is positive")
case n if n < 0:
print(f"{n} is negative")
case 0:
print("Zero")
case _:
print("Unknown number")
Simple conditions
# Define a function to calculate the tax based on income
def calculate_tax(income):
match income:
case x if x <= 10000:
tax = x * 0.1
case x if 10000 < x <= 50000:
tax = 10000 * 0.1 + (x - 10000) * 0.2
case x if x > 50000:
tax = 10000 * 0.1 + 40000 * 0.2 + (x - 50000) * 0.3
return tax
# Test the function
print("Tax for $5000:", calculate_tax(5000))
# Tax for $5000: 500.0
print("Tax for $25000:", calculate_tax(25000))
# Tax for $25000: 4000.0
print("Tax for $75000:", calculate_tax(75000))
# Tax for $75000: 17000.0
Interruption of a control flow:
“break statement”
# Example using a while loop
number = 0
while number < 5:
print(number)
if number == 3:
break # Exit the loop when number reaches 3
number += 1
print("Loop ended")
“continue statement”
# Example using a for loop
for i in range(5):
if i == 2:
continue # Skip the rest of the loop when i is 2
print(i)
With return value
# Define a function to calculate the square of a number
def square(x):
return x ** 2 # Return the square of the input value
# Call the function and store the result in a variable
result = square(5)
# Print the result
print("Square of 5 is:", result)
With return value
# Define a function to print a message and return
def print_and_return():
print("Function execution is complete.")
return # No value is returned
# Call the function
print_and_return()
print("After function call")
Loops:
“do-while” loop
i=7
f7 = 1
while i > 1:
f7 *= i
i -= 1
print(f'f7 is {f7}')
# Output: f7 is 5040
“for in range” loop
f7 = 1
for i in range(7, 1, -1):
f7 *= i
print(f'f7 is {f7}') # Output: f7 is 5040
“for-in” loop
# Example with a list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
# apple
# banana
# cherry
“while” loop
# Initialize a counter
i=0
# Define a while loop
while i < 5:
print(i)
i += 1 # Increment the counter
# 0
# 1
# 2
# 3
# 4
Endless loop
while True:
# statements
Enumerations
Enumerations, or enums, are a data type that consists of a
set of named values called elements or members. Enums
are used to represent a collection of related constants in a
readable and maintainable way. They enhance code clarity
and safety by providing meaningful names for sets of
values, reducing errors from using arbitrary numbers or
strings. Enums are commonly used in scenarios like defining
states, categories, or types where a variable can only take
one out of a small set of possible values. This makes the
code more intuitive and less prone to mistakes.
Base member value
from enum import Enum
# Define an enumeration class
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# Access the value of an enumeration member
red_value = Color.RED.value
print("Value of RED:", red_value)
# Output: Value of RED: 1
Base type
from enum import Enum
# Define an enumeration class
class DataType(Enum):
INTEGER = 42
FLOAT = 3.14
STRING = "hello"
CUSTOM_OBJECT = {"name": "John", "age": 30}
# Accessing enumeration members and their data types
print("Integer value:", DataType.INTEGER.value, "Type:",
type(DataType.INTEGER.value))
# Integer value: 42 Type: <class 'int'>
print("Float value:", DataType.FLOAT.value, "Type:",
type(DataType.FLOAT.value))
# Float value: 3.14 Type: <class 'float'>
print("String value:", DataType.STRING.value, "Type:",
type(DataType.STRING.value))
# String value: hello Type: <class 'str'>
print("Custom object value:",
DataType.CUSTOM_OBJECT.value, "Type:",
type(DataType.CUSTOM_OBJECT.value))
# Custom object value: {'name': 'John', 'age': 30} Type:
<class 'dict'>
Conversion from a string
from enum import Enum
# Define an enumeration class
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# Convert a string to an enumeration member
def string_to_enum(string_value):
try:
enum_member = Color[string_value]
return enum_member
except KeyError:
print(f"No enum member found for {string_value}")
return None
# Test the conversion
color_string = "GREEN"
color_enum_member = string_to_enum(color_string)
if color_enum_member:
print(f"Enum member for {color_string}:
{color_enum_member}")
# Enum member for GREEN: Color.GREEN
Converting to a String
from enum import Enum
# Define an enumeration class
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# Convert an enumeration member to a string
def enum_to_string(enum_member):
return str(enum_member) # Using str() function
# Test the conversion
color_enum_member = Color.GREEN
color_string = enum_to_string(color_enum_member)
print(f"String representation: {color_string}")
# String representation: Color.GREEN
# Alternatively, directly access the name attribute
color_string = color_enum_member.name
print(f"String representation (using name attribute):
{color_string}")
# String representation (using name attribute): GREEN
Definition and initialization
from enum import Enum
class Season(Enum):
Summer, Fall, Winter, Spring = range(4)
summer = Season.Summer
winter = Season.Winter
print(summer) # Season.Summer
print(winter) # Season.Winter
Enums comparison
from enum import Enum
class Size(Enum):
xs, s, m, l, xl = range(5)
small = Size.s
large = Size.l
print("is l > s:", large.value > small.value)
# is l > s: True
Explicitly set base value
from enum import Enum
class Season(Enum):
Summer = 1
Fall = 2
Winter = 3
Spring = 4
winter = Season.Winter
baseWinter = winter.value
print(baseWinter) # 3
Get the list of values
from enum import Enum
class Season(Enum):
Summer, Fall, Winter, Spring = range(4)
values = list(Season)
print(values)
print(values[0])
# [<Season.Summer: 0>, <Season.Fall: 1>,
<Season.Winter: 2>, <Season.Spring: 3>]
# Season.Summer
Initializing from a base value
from enum import Enum
class Season(Enum):
Summer = 0
Fall = 1
Winter = 2
Spring = 3
winter = Season(2)
# winter is Season.Winter
print(winter) # Season.Winter
Exceptions Handling
Exceptions handling is a programming technique used to
manage unexpected or erroneous situations that may occur
during runtime. When a program encounters an exceptional
condition (e.g., division by zero, file not found), it throws an
exception, which disrupts the normal flow of execution.
Catch all exceptions
class IsNoneException(Exception):
pass
class IsEmptyException(Exception):
pass
def throw_when_null_or_empty(data):
if data is None:
raise IsNoneException()
if len(data) == 0:
raise IsEmptyException()
try:
throw_when_null_or_empty(None)
except Exception as e:
print("Error happened " + e.__class__.__name__)
# Error happened IsNoneException
Catch the specific exception
class IsNoneException(Exception):
pass
class IsEmptyException(Exception):
pass
def throw_when_null_or_empty(data):
if data is None:
raise IsNoneException()
if len(data) == 0:
raise IsEmptyException()
try:
throw_when_null_or_empty([])
except IsNoneException:
print("list is not specified")
except IsEmptyException:
print("list is empty")
# list is empty
Define an exception type
class SimpleException(Exception):
pass
raise SimpleException("Oops!")
Guaranteed code execution
def throw_if_true(param):
try:
if param:
raise OSError("test exception")
except OSError:
print("except")
finally:
print("finally")
throw_if_true(True)
# printed: "except" and "finally"
throw_if_true(False)
# printed only "finally"
If no exception occurred
def throw_if_true(param):
try:
if param:
raise OSError("test exception")
except OSError:
print("except")
else:
print("else")
throw_if_true(True)
# printed: "except"
throw_if_true(False)
# printed only "else"
Method throwing an exception
# any method can throw an error
def method_with_exception():
raise Exception("test exception")
method_with_exception()
# Exception: test exception
Re-throw exceptions
def method_with_exception():
try:
raise Exception("test exception")
except Exception as ex:
# implementation of any partial procesing
# and send error to the calling code
raise ex
try:
method_with_exception()
except Exception as e:
print(e.args[0])
# test exception
Throw an exception
class Seller:
def __init__(self):
self.cars = []
def sell(self):
if len(self.cars) == 0:
raise Exception("No cars for sale")
seller = Seller()
try:
seller.sell()
except Exception as e:
print(e.args[0])
# e.args[0] is "No cars for sale"
Extensions
Extensions in programming languages allow developers to
enhance existing types or classes without modifying their
source code. They provide a way to add new functionality,
methods, or properties to types that are already defined.
Adding object methods
from math import *
excluded_methods = frozenset(["__module__",
"__qualname__"])
def class_extend(cls):
class Meta(type):
def __new__(mcs, name, bases, attrs):
for name, value in attrs.items():
if name not in excluded_methods:
setattr(cls, name, value)
return cls
return Meta
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class Point(metaclass=class_extend(Point)):
def distance_to(self, p2):
d1 = pow(self.x - p2.x, 2)
d2 = pow(self.y - p2.y, 2)
return sqrt(d1 + d2)
point1 = Point(1, 2)
point2 = Point(2, 3)
distance = point1.distance_to(point2)
print(f"{distance = }")
# distance = 1.4142135623730951
Functions
Functions in programming are blocks of reusable code that
perform a specific task. They allow developers to
encapsulate logic, promote code reusability, and enhance
readability by breaking down complex operations into
smaller, manageable parts.
Array of parameters
def get_avg(*values):
if len(values) == 0:
return 0
sum_v = 0
for value in values:
sum_v += value
return sum_v / len(values)
avg = get_avg(1, 2, 3, 4)
print(f"{avg = }") # avg is 2.5
In/Out parameters
def swap_strings(s1, s2):
tmp = s1[0]
s1[0] = s2[0]
s2[0] = tmp
s1 = ["A"]
s2 = ["B"]
swap_strings(s1, s2)
print(f"s1[0] is {s1[0]}, s2[0] is {s2[0]}")
# s1[0] is "B", s2[0] is "A"
Multiple return values
def get_first_last(ar):
if len(ar) == 0:
return -1, -1
return ar[0], ar[-1]
ar = [2, 3, 5]
first, last = get_first_last(ar)
print(f"first is {first}") # first is 2
print(f"last is {last}") # last is 5
Optional parameter values
# Using Default Parameter Values in Python
def say_goodbye(message="Goodbye!"):
print(message)
say_goodbye()
# prints "Goodbye!"
say_goodbye("See you")
# prints "See you"
# Before Using Default Parameters
def old_say_goodbye(message=None):
if message is None:
message = "Goodbye!"
print(message)
old_say_goodbye()
# prints "Goodbye!"
old_say_goodbye("See you")
# prints "See you"
Out parameters
# in Python, you can't change param reference
def get_sum(summ, n1, n2):
summ.append(n1 + n2):
ar_sum = []
get_sum(ar_sum, 5, 3)
# ar_sum is [13]
Recursion
def fibonacci(x):
return x if x <= 1 else fibonacci(x - 1) + fibonacci(x - 2)
f10 = fibonacci(10)
print(f"f10 is {f10}") # f10 is 55
Variable parameters
def print5(data):
if len(data) > 5:
data = data[0: 5]
print(data)
print5("1234567") # prints: 12345
With return value
def get_sum(n1, n2):
return n1 + n2
result = get_sum(5, 3)
print(f"{result = }") # result is 8
Without any parameters
def say_goodbye():
print("Goodbye!")
say_goodbye()
Without any return value
def add_3_and_print(value):
print(value + 3)
add_3_and_print(5) # 8
Generic Types
Generic types in programming languages allow developers
to define classes, functions, or interfaces that can work with
various data types without specifying them beforehand. This
flexibility enhances code reusability and type safety by
enabling components to be more generic and adaptable to
different scenarios.
Class conformity
from typing import TypeVar, Generic
class Vehicle:
def test(self):
print(f"test: {self}")
class Car(Vehicle):
pass
class Truck:
pass
T = TypeVar('T', bound=Vehicle)
class Service(Generic[T]):
def __init__(self):
selt.v_list = list[T]()
def add(self, item: T):
self.v_list.append(item)
def test(self):
for item in self.v_list:
item.test()
service = Service[Vehicle]()
service.add(Vehicle())
service.add(Car())
# Warning: Expected type 'Vehicle'
service.add(Truck())
service.test()
Default value
from typing import TypeVar, Generic, Type T = TypeVar('T')
class Size(Generic[T]):
def __init__(self, width: T, height: T):
self.width = width
self.height = height
def reset(self):
self.width = type(self.width)()
self.height = type(self.height)()
def print(self):
print(f{[{self.width}; {self.height}]})
size_int = Size[int](5, 9)
size_int.print()
# prints: [5; 9]
size_int.reset()
size_int.print()
# prints: [0; 0]
Generic classes
from typing import TypeVar, Generic
T = TypeVar('T')
class Size(Generic[T]):
def __init__(self, width: T, height: T):
self.width = width
self.height = height
def as_text(self):
return f"[{self.width}; {self.height}]"
size_int = Size[int](5, 8)
text_int = size_int.as_text()
# text_int is "[5; 8]"
print(f"{text_int=}")
print(f"{text_float=}")
Generic collections
# List of integer
int_list = list[int]()
int_list.append(5)
print(f"{int_list = }")
# Dictionary
dic = dict[int, str]()
dic[1] = "one"
print(f"{dic = }")
# Set
set_float = set[float]()
set_float.add(3.14)
print(f"{set_float = }")
# nt_list = [5]
# dic = {1: 'one'}
# set_float = {3.14}
Generic methods
from typing import TypeVar
T = TypeVar('T')
def swap(v1: list[T], v2: list[T]):
v1[0], v2[0] = v2[0], v1[0]
n1 = [5]
n2 = [7]
swap(n1, n2)
# n1[0] is 7, n2[0] is 5
s1 = ["cat"]
s2 = ["dog"]
swap(s1, s2)
# s1[0] is "B", s2[0] is "A"
print(f'{n1 = }, {n2 = }')
print(f'{s1 = }, {s2 = }')
Interface conformity
from abc import ABC, abstractmethod
from typing import TypeVar, Generic
class Vehicle(ABC):
@abstractmethod
def test(self):
pass
class Car(Vehicle):
def test(self):
print(f"test {self}")
T = TypeVar('T', bound=Vehicle)
class Service(Generic[T]):
def __init__(self):
self.v_list = list[T]()
def add(self, item: T):
self.v_list.append(item)
def test(self):
for item in self.v_list:
item.test()
service = Service[Car]()
service.add(Car())
service.test()
Substitution principle
class Vehicle:
def test(self):
print(f"test {self}")
class Car(Vehicle):
pass
class Truck(Vehicle):
pass
lst = list[Vehicle]()
lst.append(Vehicle())
lst.append(Car())
lst.append(Truck())
for vehicle in lst:
vehicle.test()
Initializing of Types
Initializing types refers to the process of setting initial
values or states for variables, objects, or data structures in
a program. This process ensures that entities in the program
start with predefined values, which are often crucial for
correct functioning and behavior.
Classes:
With a constructor
class Phone:
def __init__(self, model):
self.model = model
class Employee:
def __init__(self, first_name, last_name, phone):
self.first_name = first_name
self.last_name = last_name
self.phone = phone
# Create instances
nokia_phone = Phone("Nokia 6610")
kim = Employee("Victorya", "Kim", Phone("IPhone 11 Pro"))
# Access and print phone model
print(kim.phone.model) # Iphone 11 Pro
Without any constructor
class Phone:
pass # No explicit constructor needed
class Employee:
pass # No explicit constructor needed
kim = Employee()
kim.firstName = "Victorya"
kim.lastName = "Kim"
kim.phone = Phone()
kim.phone.model = "IPhone 5"
# list of Employee
class Employee:
def __init__(self, first_name, last_name):
self.firstName = first_name
self.lastName = last_name
def __iter__(self):
return self
def __next__(self):
if self.current > self.high
raise StopIteration
else:
result = self.current
self.current += self.step
return result