Python refresher
This post is a quick refresher on python for experience engineer to start writing code.
Comments in Python
Single-line Comments:
- Start with a hash symbol (
#). - Everything after the
#on the same line is ignored by the Python interpreter.
# This is a single-line comment
x = 5 # This is an inline commentMulti-line Comments (Docstrings):
- Enclosed within triple quotes (
"""or'''). - Often used for documenting functions, classes, and modules.
"""
This is a multi-line comment.
It can span multiple lines.
"""
def my_function():
"""This is a docstring for the my_function."""
passUse docstrings for functions, classes, and modules: Docstrings provide a standard way to document your code and are often used by tools like Sphinx to generate documentation.
def calculate_area_of_circle(radius):
"""
Calculates the area of a circle.
Args:
radius: The radius of the circle.
Returns:
The area of the circle.
"""
import math
return math.pi * radius * radius
# Get user input for radius
radius = float(input("Enter the radius of the circle: "))
# Calculate and print the area
area = calculate_area_of_circle(radius)
print(f"The area of the circle is: {area}")Variables and Data Types
Python is a dynamically typed language. Following are few highlights.
No Explicit Type Declarations: You don’t need to explicitly declare the data type of a variable before assigning a value to it. Following is few example.
x = 10 # x is automatically inferred as an integer
x = "hello" # Now x is a string
my_variable = None # It represents the absence of a value.
temperature = 25.5
is_raining = True
Type Inference: Python automatically determines the data type of a variable based on the value assigned to it.
Flexibility: This dynamic typing allows for more flexibility and rapid development, as you don’t have to worry about type declarations.
Type Checking (Optional): You can use type hints to provide information about the expected data types for variables and function arguments. This is optional but can improve code readability and help catch errors early on.
def greet(name: str) -> str:
return f"Hello, {name}!"print() is used to displays output to the console. Following is syntax.
print(value1, value2, ..., sep=' ', end='\n')value1, value2, ...: The values you want to print (can be variables, strings, numbers, etc.).sep: The separator between values (default is a space ' ').end: The character to print at the end (default is a newline '\n').
Following is example to use print.
print("Hello, world!")
print("My name is", "Alice")
print(10 + 5)
print("The result is:", 10 * 2, sep=" - ")
print("Hello", end=" ")
print("world!")input() is used to gets input from the user. Following is syntax.
input(prompt="")prompt: An optional string that is displayed to the user as a message.
Following is example for reference.
name = input("Enter your name: ")
print("Hello,", name)Combining print() and input()
age = int(input("Enter your age: "))
print("You are", age, "years old.")Operators
Arithmetic operators
Arithmetic operators are used to perform mathematical operations on numbers. Following is example to show few.
num1 = 10
num2 = 3
sum_result = num1 + num2 # 10 + 3 = 13
difference_result = num1 - num2 # 10 - 3 = 7
product_result = num1 * num2 # 10 * 3 = 30
division_result = num1 / num2 # 10 / 3 = 3.3333333333333335
floor_division_result = num1 // num2 # 10 // 3 = 3
modulus_result = num1 % num2 # 10 % 3 = 1
exponentiation_result = num1 ** 2 # 10 ** 2 = 100
print("Sum:", sum_result)
print("Difference:", difference_result)
print("Product:", product_result)
print("Division:", division_result)
print("Floor Division:", floor_division_result)
print("Modulus:", modulus_result)
print("Exponentiation:", exponentiation_result)Comparison operators
Comparison operators are used to compare values and return a Boolean value (True or False). They are essential for making decisions in your code (e.g., within if statements).
Here’s a list of common comparison operators:
Equal to (==)
- Checks if two values are equal.
- Example:
5 == 5returnsTrue,5 == 3returnsFalse
Not Equal to (!=)
- Checks if two values are not equal.
- Example:
5 != 3returnsTrue,5 != 5returnsFalse
Greater Than (>)
- Checks if the left operand is greater than the right operand.
- Example:
5 > 3returnsTrue,3 > 5returnsFalse
Less Than (<)
- Checks if the left operand is less than the right operand.
- Example:
3 < 5returnsTrue,5 < 3returnsFalse
Greater Than or Equal To (>=)
- Checks if the left operand is greater than or equal to the right operand.
- Example:
5 >= 5returnsTrue,3 >= 5returnsFalse
Less Than or Equal To (<=)
- Checks if the left operand is less than or equal to the right operand.
- Example:
3 <= 5returnsTrue,5 <= 3returnsFalse
Following is example for reference.
x = 10
y = 5
print(x == y) # False
print(x != y) # True
print(x > y) # True
print(x < y) # False
print(x >= y) # True
print(x <= y) # False
age = 25
if age >= 18:
print("You are an adult.")
else:
print("You are a minor.")Logical operators
Logical operators are used to combine multiple Boolean expressions. They are essential for creating more complex conditions in your code.
Here are the main logical operators in Python:
and: Returns True if both operands are True, otherwise returns False.
True and True # True
True and False # False
False and True # False
False and False # Falseor: Returns True if at least one operand is True, otherwise returns False.
True or True # True
True or False # True
False or True # True
False or False # Falsenot: Inverts the truth value of the operand.
not True # False
not False # TrueExample
# and example
age = 25
has_driver_license = True
if age >= 18 and has_driver_license:
print("You are eligible to drive.")
# or example
is_raining = True
is_sunny = False
if is_raining or is_sunny:
print("It's either raining or sunny.")Order of Operations
Logical operators have an order of precedence:
notandor
You can use parentheses to override the default order of operations:
result = not (True and False) # Result will be TrueControl Flow
Control flow statements allow you to alter the order in which your Python code is executed. They give you the power to make decisions and repeat actions based on specific conditions.
if, elif, else :Used to make decisions based on conditions.
Syntax:
if condition1:
# Code to execute if condition1 is True
elif condition2:
# Code to execute if condition1 is False and condition2 is True
else:
# Code to execute if all previous conditions are FalseExample:
age = 20
if age < 18:
print("You are a minor.")
elif age >= 18 and age < 65:
print("You are an adult.")
else:
print("You are a senior.") 1 ternary operator
In Python, the ternary operator is a concise way to write conditional expressions. It allows you to evaluate a condition and return one of two values based on whether the condition is True or False. The syntax is:
value_if_true if condition else value_if_falseExample 1: Basic Usage
x = 10
y = 20
# Use the ternary operator to find the maximum of two numbers
max_value = x if x > y else y
print("Max value:", max_value)Example 2: Ternary Operator with Lists
numbers = [1, 2, 3, 4, 5]
# Use ternary operator to filter even numbers
filtered_numbers = [x if x % 2 == 0 else "Odd" for x in numbers]
print("Filtered list:", filtered_numbers)
# Filtered list: ['Odd', 2, 'Odd', 4, 'Odd']for loop Used to iterate over a sequence of elements (like lists, tuples, strings, or ranges).
Syntax
for item in sequence:
# Code to execute for each itemExample
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)while Loop: Used to repeat a block of code as long as a condition is True.
Syntax
while condition:
# Code to execute as long as condition is TrueExample
count = 0
while count < 5:
print(count)
count = count + 1break: Exits the loop immediately.
continue: Skips the current iteration of the loop and moves to the next one.
for i in range(10):
if i == 5:
break # Exit the loop when i reaches 5
if i % 2 == 0:
continue # Skip even numbers
print(i)Data Structures
Data structures are fundamental to organizing and storing data effectively in your programs. Python offers several built-in data structures:
Lists
- Ordered Collection: Elements are stored in a specific order.
- Mutable: You can change the elements of a list after it’s created.
- Syntax:
my_list = [element1, element2, ...]
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed_list = [10, "hello", True]Key Operations:
Accessing elements: my_list[index] (e.g., fruits[0] # Accesses the first element)
Slicing: my_list[start:end] (e.g., fruits[1:3] # Accesses elements from index 1 to 2 , here end is excluded)
Adding elements: my_list.append(), my_list.insert()
my_list.append(item):
- Purpose: Adds a single
itemto the end of the list. - Syntax:
list.append(item) - Behavior: It’s equivalent to
list[len(list):] = [item]. The new element is always placed at the last available index. - Efficiency: Generally very efficient (amortized O(1) time complexity) because it doesn’t require shifting existing elements.
- Return Value:
None(modifies the list in-place).
my_list = [10, 20, 30]
my_list.append(40)
print(my_list)
# Output: [10, 20, 30, 40]
my_list.append("hello")
print(my_list)
# Output: [10, 20, 30, 40, "hello"]my_list.insert(index, item):
- Purpose: Inserts a single
itemat a specifiedindexin the list. - Syntax:
list.insert(index, item) - Behavior:
- If
indexis less than or equal to 0, the item is inserted at the beginning of the list. - If
indexis greater than or equal to the length of the list, the item is inserted at the end (similar toappend()). - Otherwise, the item is inserted at the given
index, and all subsequent elements are shifted one position to the right to make space. - Efficiency: Can be less efficient (O(n) time complexity) because inserting an element in the middle requires shifting all elements from that point onwards.
- Return Value:
None(modifies the list in-place).
my_list = [10, 20, 30, 40]
# Insert 15 at index 1
my_list.insert(1, 15)
print(my_list)
# Output: [10, 15, 20, 30, 40]
# Insert 5 at the beginning (index 0)
my_list.insert(0, 5)
print(my_list)
# Output: [5, 10, 15, 20, 30, 40]
# Insert 50 at an index beyond the current length (behaves like append)
my_list.insert(100, 50) # Length is 6, index 100 is out of bounds
print(my_list)
# Output: [5, 10, 15, 20, 30, 40, 50]Removing elements:
my_list.remove(value):
- Purpose: Removes the first occurrence of a specified
valuefrom the list. - Syntax:
list.remove(value) - Argument: Takes the
valueof the item you want to remove. - Behavior:
- It searches the list from the beginning.
- If the
valueis found, its first instance is removed. - If the
valueis not found in the list, it raises aValueError. - Return Value:
None. It modifies the list in-place. - Efficiency: In the worst case (the item is at the end or not present), it’s O(n) time complexity because it might have to scan the entire list and then shift subsequent elements.
my_list = [10, 20, 30, 20, 40]
my_list.remove(20) # Removes the first 20
print(my_list)
# Output: [10, 30, 20, 40]
my_list.remove(40)
print(my_list)
# Output: [10, 30, 20]
# my_list.remove(50) # This would raise a ValueError because 50 is not in the listmy_list.pop([index])
- Purpose: Removes an element from the list based on its index. It also returns the removed element.
- Syntax:
list.pop([index])(theindexargument is optional) - Argument:
- If
indexis provided, it removes the element at that specific index. - If
indexis not provided (i.e.,my_list.pop()), it removes and returns the last element of the list. - Behavior:
- If the list is empty and
pop()is called without an index, or if the providedindexis out of range, it raises anIndexError. - Return Value: The element that was removed from the list.
- Efficiency:
- Removing the last element (
my_list.pop()): O(1) time complexity (very efficient). - Removing an element from a specific index (
my_list.pop(index)): O(n) time complexity, as it requires shifting subsequent elements.
my_list = [10, 20, 30, 40, 50]
# Remove the element at index 2 (which is 30)
removed_element = my_list.pop(2)
print(my_list)
# Output: [10, 20, 40, 50]
print("Removed:", removed_element)
# Output: Removed: 30
# Remove the last element (which is 50)
last_element = my_list.pop()
print(my_list)
# Output: [10, 20, 40]
print("Removed last:", last_element)
# Output: Removed last: 50
# my_list.pop(100) # This would raise an IndexError because index 100 is out of range
# empty_list = []
# empty_list.pop() # This would raise an IndexError because the list is emptyModifying elements: my_list[index] = new_value
Tuples
Similar to lists, but immutable.
Syntax: my_tuple = (element1, element2, ...)
coordinates = (10, 20)
days_of_week = ("Monday", "Tuesday", "Wednesday")Key Characteristics:
- Once created, you cannot change the elements of a tuple.
- Used for representing data that should not be modified.
Creating Tuples
a) Empty Tuple:
empty_tuple = ()
print(empty_tuple) # Output: ()
print(type(empty_tuple)) # Output: <class 'tuple'>b) Tuple with One Element (Crucial Syntax!):
single_element_tuple = (1,) # The comma is essential!
print(single_element_tuple) # Output: (1,)
print(type(single_element_tuple)) # Output: <class 'tuple'>
not_a_tuple = (1) # This is just an integer in parentheses
print(not_a_tuple) # Output: 1
print(type(not_a_tuple)) # Output: <class 'int'>c) Tuple with Multiple Elements:
my_tuple = (1, 2, 3)
print(my_tuple) # Output: (1, 2, 3)
another_tuple = ("apple", 3.14, True)
print(another_tuple) # Output: ('apple', 3.14, True)
# Parentheses are often optional for multiple elements, but good practice
tuple_without_parens = 10, 20, 30
print(tuple_without_parens) # Output: (10, 20, 30)
print(type(tuple_without_parens)) # Output: <class 'tuple'>Accessing Elements (Indexing)
Like lists and strings, tuple elements are accessed by their zero-based index.
my_tuple = ("red", "green", "blue", "yellow")
print(my_tuple[0]) # Output: red (first element)
print(my_tuple[2]) # Output: blue (third element)
print(my_tuple[-1]) # Output: yellow (last element)
print(my_tuple[-3]) # Output: green (third from last)Slicing Tuples
Slicing works identically to lists and strings. It extracts a portion of the tuple, creating a new tuple. The end index is excluded.
my_tuple = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
print(my_tuple[2:5]) # Elements from index 2 up to (but not including) 5
# Output: (2, 3, 4)
print(my_tuple[:4]) # Elements from the beginning up to (but not including) 4
# Output: (0, 1, 2, 3)
print(my_tuple[6:]) # Elements from index 6 to the end
# Output: (6, 7, 8, 9)
print(my_tuple[::2]) # Every second element (step of 2)
# Output: (0, 2, 4, 6, 8)
print(my_tuple[::-1]) # Reverse the tuple
# Output: (9, 8, 7, 6, 5, 4, 3, 2, 1, 0)Immutability (Key Characteristic)
You cannot change, add, or remove elements from a tuple after it’s created.
my_tuple = (1, 2, 3)
# my_tuple[0] = 10 # This will raise a TypeError: 'tuple' object does not support item assignment
# my_tuple.append(4) # This will raise an AttributeError: 'tuple' object has no attribute 'append'
# del my_tuple[0] # This will raise a TypeError: 'tuple' object doesn't support item deletionTuple Unpacking (Powerful Feature)
Tuple unpacking allows you to assign elements of a tuple to individual variables. This is extremely useful for returning multiple values from functions.
coordinates = (10, 20)
x, y = coordinates # Unpacking
print(f"X: {x}, Y: {y}") # Output: X: 10, Y: 20
# Swapping variables (classic use case)
a = 5
b = 10
a, b = b, a # Swaps values using tuple packing/unpacking
print(f"a: {a}, b: {b}") # Output: a: 10, b: 5
# Function returning multiple values
def get_user_info():
return "Alice", 30, "alice@example.com"
name, age, email = get_user_info()
print(f"Name: {name}, Age: {age}, Email: {email}")
# Output: Name: Alice, Age: 30, Email: alice@example.comYou can use the * operator to capture multiple remaining elements into a list:
person = ("Bob", 25, "Software Engineer", "New York")
name, age, *details = person # details will be ['Software Engineer', 'New York']
print(f"Name: {name}, Age: {age}, Details: {details}")
# Output: Name: Bob, Age: 25, Details: ['Software Engineer', 'New York']Common Tuple Operations
Get Dilip Kumar’s stories in your inbox
Join Medium for free to get updates from this writer.
Concatenation: Use + to join tuples (creates a new tuple).
t1 = (1, 2)
t2 = (3, 4)
t3 = t1 + t2
print(t3) # Output: (1, 2, 3, 4)Repetition: Use * to repeat tuple elements (creates a new tuple).
t = (0,) * 5
print(t) # Output: (0, 0, 0, 0, 0)Length: Use len() to get the number of elements.
my_tuple = (1, 2, 3)
print(len(my_tuple)) # Output: 3Membership: Use in or not in to check if an element exists.
my_tuple = (10, 20, 30)
print(20 in my_tuple) # Output: True
print(50 not in my_tuple) # Output: TrueIteration: Use a for loop.
for item in ("A", "B", "C"):
print(item)
# Output:
# A
# B
# CCounting Elements: Use count(value) to find how many times a value appears.
my_tuple = (1, 2, 2, 3, 2)
print(my_tuple.count(2)) # Output: 3Finding Index: Use index(value) to find the index of the first occurrence of a value. Raises ValueError if not found.
my_tuple = ('a', 'b', 'c')
print(my_tuple.index('b')) # Output: 1
# my_tuple.index('d') # ValueErrorDictionaries
Dictionaries are defined by curly braces {} with key-value pairs separated by colons : and individual pairs separated by commas ,.
Key Characteristics:
- Unordered in older Python versions (Python 3.6+ generally maintain insertion order): While newer Python versions maintain insertion order, you should not rely on it for logic that requires a specific order if you’re working with older codebases or want maximum compatibility.
- Mutable: You can change, add, or remove items after creation.
- Keys must be unique: No two keys in a dictionary can be the same. If you try to add a duplicate key, the new value will overwrite the old one.
- Keys must be immutable: Keys can be strings, numbers, or tuples. Lists and other mutable objects cannot be used as keys.
Sample code
# 1. Creating an empty dictionary
empty_dict = {}
print(f"Empty dictionary: {empty_dict}") # Output: Empty dictionary: {}
# 2. Creating a dictionary with initial key-value pairs
student = {
"name": "Alice",
"age": 20,
"major": "Computer Science",
"gpa": 3.8
}
print(f"Student dictionary: {student}")
# Output: Student dictionary: {'name': 'Alice', 'age': 20, 'major': 'Computer Science', 'gpa': 3.8}
# 3. Accessing values using keys (the most common way)
print(f"Student's name: {student['name']}") # Output: Student's name: Alice
print(f"Student's major: {student['major']}") # Output: Student's major: Computer Science
# 4. Using the .get() method to access values (safer for non-existent keys)
# If the key doesn't exist, .get() returns None by default, or a specified default value
print(f"Student's age: {student.get('age')}") # Output: Student's age: 20
print(f"Student's year (using .get() with default): {student.get('year', 'N/A')}")
# Output: Student's year (using .get() with default): N/A
print(f"Student's address (using .get() without default): {student.get('address')}")
# Output: Student's address (using .get() without default): None
# 5. Accessing a non-existent key directly will raise a KeyError
try:
print(student['address'])
except KeyError as e:
print(f"Error: {e} - 'address' key does not exist.")
# Output: Error: 'address' - 'address' key does not exist.Adding, Modifying, and Deleting Items
Dictionaries are mutable, meaning you can change them after they are created.
student = {
"name": "Alice",
"age": 20,
"major": "Computer Science"
}
print(f"Original dictionary: {student}")
# 1. Adding a new key-value pair
student["university"] = "Tech University"
print(f"After adding 'university': {student}")
# Output: After adding 'university': {'name': 'Alice', 'age': 20, 'major': 'Computer Science', 'university': 'Tech University'}
# 2. Modifying an existing value
student["age"] = 21
print(f"After modifying 'age': {student}")
# Output: After modifying 'age': {'name': 'Alice', 'age': 21, 'major': 'Computer Science', 'university': 'Tech University'}
# 3. Deleting an item using del keyword
del student["major"]
print(f"After deleting 'major': {student}")
# Output: After deleting 'major': {'name': 'Alice', 'age': 21, 'university': 'Tech University'}
# 4. Removing an item using .pop() method (returns the removed value)
gpa_value = student.pop("gpa", "N/A") # 'gpa' wasn't in the dict, so it returns 'N/A'
print(f"Popped GPA (not found): {gpa_value}")
print(f"After popping 'gpa' (not found): {student}")
# Output: Popped GPA (not found): N/A
# Output: After popping 'gpa' (not found): {'name': 'Alice', 'age': 21, 'university': 'Tech University'}
student["gpa"] = 3.9 # Add 'gpa' back for demonstration
removed_name = student.pop("name")
print(f"Popped name: {removed_name}")
print(f"After popping 'name': {student}")
# Output: Popped name: Alice
# Output: After popping 'name': {'age': 21, 'university': 'Tech University', 'gpa': 3.9}
# 5. Removing the last inserted item (Python 3.7+ guaranteed) using .popitem()
# Raises KeyError if dictionary is empty
last_item = student.popitem()
print(f"Popped last item: {last_item}") # Output: Popped last item: ('gpa', 3.9)
print(f"After popping last item: {student}")
# Output: After popping last item: {'age': 21, 'university': 'Tech University'}
# 6. Clearing all items from the dictionary
student.clear()
print(f"After clearing: {student}") # Output: After clearing: {}Iterating Through Dictionaries
You can iterate over dictionary keys, values, or both.
grades = {
"Math": "A",
"Physics": "B+",
"Chemistry": "A-",
"History": "C"
}
# 1. Iterating over keys (default)
print("--- Iterating over keys ---")
for subject in grades:
print(f"Subject: {subject}")
# Output:
# Subject: Math
# Subject: Physics
# Subject: Chemistry
# Subject: History
# 2. Iterating over values using .values()
print("\n--- Iterating over values ---")
for grade in grades.values():
print(f"Grade: {grade}")
# Output:
# Grade: A
# Grade: B+
# Grade: A-
# Grade: C
# 3. Iterating over both keys and values using .items() (most common for both)
print("\n--- Iterating over key-value pairs ---")
for subject, grade in grades.items():
print(f"Subject: {subject}, Grade: {grade}")
# Output:
# Subject: Math, Grade: A
# Subject: Physics, Grade: B+
# Subject: Chemistry, Grade: A-
# Subject: History, Grade: C
# 4. Checking if a key exists
print("\n--- Checking for key existence ---")
if "Math" in grades:
print("Math grades exist.") # Output: Math grades exist.
if "Biology" not in grades:
print("Biology grades do not exist.") # Output: Biology grades do not exist.Dictionary Comprehension
dictionary comprehensions provide a concise way to create dictionaries.
# 1. Creating a dictionary from a list of items
fruits = ["apple", "banana", "cherry"]
fruit_lengths = {fruit: len(fruit) for fruit in fruits}
print(f"Fruit lengths: {fruit_lengths}")
# Output: Fruit lengths: {'apple': 5, 'banana': 6, 'cherry': 6}
# 2. Squaring numbers
squares = {x: x**2 for x in range(5)}
print(f"Squares: {squares}")
# Output: Squares: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 3. Filtering items while creating
original_dict = {"a": 1, "b": 2, "c": 3, "d": 4}
even_values = {key: value for key, value in original_dict.items() if value % 2 == 0}
print(f"Even values: {even_values}")
# Output: Even values: {'b': 2, 'd': 4}
# 4. Swapping keys and values (if values are unique and hashable)
inverted_dict = {value: key for key, value in original_dict.items()}
print(f"Inverted dictionary: {inverted_dict}")
# Output: Inverted dictionary: {1: 'a', 2: 'b', 3: 'c', 4: 'd'}Sets
Unordered collections of unique elements. You can add or remove elements.
Syntax: my_set = {element1, element2, ...}
unique_numbers = {1, 2, 3, 3, 4, 4} # Set will contain only 1, 2, 3, 4Key Operations:
- Checking for membership:
element in my_set - Set operations:
union(),intersection(),difference()
set1 = {1, 2, 3}
set2 = {3, 4, 5}
# union example
union_set = set1.union(set2) # or set1 | set2
print(union_set) # Output: {1, 2, 3, 4, 5}
# intersection example
intersection_set = set1.intersection(set2) # or set1 & set2
print(intersection_set) # Output: {3}
# difference example
difference_set = set1.difference(set2) # or set1 - set2
print(difference_set) # Output: {1, 2}Functions
In Python, a function is a block of reusable code that performs a specific task. It helps to organize your code, improve readability, and avoid code duplication.
Defining a Function:
You define a function using the def keyword followed by the function name, parentheses for parameters (if any), and a colon. The 1 code block within the function is indented.
def greet(name):
"""This function greets the person passed in as a parameter."""
print("Hello, " + name + "!")Calling a Function:
To use a function, you “call” it by using its name followed by parentheses.
greet("Alice") # Output: Hello, Alice!Parameters and Arguments:
- Parameters: Variables defined within the parentheses of a function definition. They act as placeholders for values that will be passed to the function.
- Arguments: The actual values that are passed to a function when it’s called.
def add(x, y):
"""This function adds two numbers."""
return x + y
result = add(5, 3) # 5 and 3 are arguments
print(result) # Output: 8Return Statement:
The return statement specifies the value that a function should return. If no return statement is used, the function will return None by default.
def square(x):
return x * x
result = square(4)
print(result) # Output: 16Function Scope: Variables defined within a function are local to that function and cannot be accessed outside of it.
Global Variables: Variables defined outside of any function are global and can be accessed from anywhere in the code.
Default Arguments: You can provide default values for function parameters.
def greet(name, greeting="Hello"):
print(greeting + ", " + name + "!")
greet("Bob") # Output: Hello, Bob!
greet("Alice", "Hi") # Output: Hi, Alice!Lambda Functions (Anonymous Functions)
In Python, lambda functions are small, anonymous functions that are defined using the lambda keyword. They are often used for simple, one-off operations.
Syntax:
lambda arguments: expressionlambda: The keyword that signifies the start of a lambda function.arguments: The parameters the function accepts.expression: The single expression that the function evaluates and returns.
# Define a lambda function to square a number
square = lambda x: x * x
result = square(5) # Calculate 5 squared
print(result) # Output: 25Common Use Cases:
map() function: Applying a function to each element of an iterable.
numbers = [1, 2, 3, 4]
squared_numbers = list(map(lambda x: x * x, numbers))
print(squared_numbers) # Output: [1, 4, 9, 16]filter() function: Filtering elements from an iterable based on a condition.
numbers = [1, 2, 3, 4, 5]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # Output: [2, 4]sorted() function: Sorting a list based on a custom key.
names = ["Alice", "bob", "Charlie"]
sorted_names = sorted(names, key=lambda x: x.lower())
print(sorted_names) # Output: ['Alice', 'bob', 'Charlie']main method
In Python, there’s no strict equivalent to the main() method as you might find in languages like Java or C++. However, you can achieve a similar effect using a few common approaches:
Using if __name__ == "__main__":
This is the most common and recommended way to define the entry point of your Python script.
def main():
# Code to be executed when the script is run directly
if __name__ == "__main__":
main()__name__is a special variable that holds the name of the current module.- When you run a Python script directly (e.g.,
python my_script.py),__name__is set to"__main__". - If the script is imported as a module in another script,
__name__will be set to the module's name. - This allows you to write reusable code that can be both executed directly and imported as a module.
Object-Oriented Programming (OOP)
OOP is a programming paradigm that organizes code around “objects” that encapsulate data (attributes) and methods (functions) that operate on that data.
Classes: A blueprint or template for creating objects. Defines the attributes (data) and methods (behaviors) that objects of that class will have.
Objects: Instances of a class. Each object has its own set of attribute values
Attributes: Characteristics or properties of an object. Represented by variables within a class.
Methods: Functions that belong to a class. Define the actions or behaviors that objects of the class can perform.
Example
class Dog:
"""A simple Dog class"""
def __init__(self, name, breed): # Constructor (special method)
self.name = name
self.breed = breed
def bark(self):
print("Woof!")
def display_info(self):
print(f"Name: {self.name}")
print(f"Breed: {self.breed}")
# Create objects (instances) of the Dog class
my_dog = Dog("Buddy", "Golden Retriever")
your_dog = Dog("Coco", "Poodle")
# Access attributes
print(my_dog.name) # Output: Buddy
# Call methods
my_dog.bark() # Output: Woof!
your_dog.display_info()Inheritance: Creating subclasses and inheriting properties from parent classes.
super(): The super().__init__(name) call in the Dog class's constructor invokes the constructor of the parent class to initialize the name attribute.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print("Generic animal sound")
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # Call the parent class's constructor
self.breed = breed
def speak(self):
print("Woof!")
class Cat(Animal):
def speak(self):
print("Meow!")
# Create objects
my_dog = Dog("Buddy", "Golden Retriever")
my_cat = Cat("Whiskers")
# Access attributes and call methods
print(my_dog.name) # Output: Buddy
print(my_dog.breed) # Output: Golden Retriever
my_dog.speak() # Output: Woof!
print(my_cat.name) # Output: Whiskers
my_cat.speak() # Output: Meow!Polymorphism
Polymorphism is a fundamental concept in Object-Oriented Programming (OOP). It allows objects of different classes to be treated as objects of a common type. This means the same method can be called on different objects, and the specific behavior will vary based on the object’s class.
class Animal:
def sound(self):
print("Generic animal sound")
class Dog(Animal):
def sound(self):
print("Woof!")
class Cat(Animal):
def sound(self):
print("Meow!")
def make_sound(animal):
animal.sound()
dog = Dog()
cat = Cat()
make_sound(dog) # Output: Woof!
make_sound(cat) # Output: Meow!Duck Typing
- Python’s dynamic nature allows for a flexible form of polymorphism known as “duck typing.”
- If an object “walks like a duck and quacks like a duck,” then it is treated as a duck.
- It focuses on the object’s behavior rather than its specific class.
def fly(bird):
bird.fly()
class Duck:
def fly(self):
print("Duck is flying")
class Airplane:
def fly(self):
print("Airplane is flying")
duck = Duck()
airplane = Airplane()
fly(duck) # Output: Duck is flying
fly(airplane) # Output: Airplane is flyingEncapsulation
Data Hiding: Making attributes private using a single underscore (_) prefix. This indicates that the attribute is intended for internal use and should not be accessed directly from outside the class.
class Employee:
def __init__(self, name, salary):
self._name = name # Private attribute
self._salary = salary
def get_name(self):
return self._name
def get_salary(self):
return self._salaryPublic Interface: You provide controlled access to the object’s data through public methods (also called getters and setters).
class Employee:
def __init__(self, name, salary):
self._name = name
self._salary = salary
def get_name(self):
return self._name
def set_name(self, new_name):
self._name = new_name
def get_salary(self):
return self._salary
def set_salary(self, new_salary):
if new_salary >= 0: # Validate salary value
self._salary = new_salary
else:
print("Invalid salary.")Private Methods
Prefixing with double underscores (__): This is the convention for indicating a method as private. For example: __private_method(self)
class MyClass:
def __init__(self):
self.__private_var = 10
def __private_method(self):
print("This is a private method.")
def public_method(self):
self.__private_method()
# Accessing private members
my_object = MyClass()
# my_object.__private_var # This will likely raise an AttributeError
# my_object.__private_method() # This will likely raise an AttributeError
my_object.public_method() # This will work, as __private_method is called within the className Mangling: When you define a method with a double underscore prefix (e.g., __private_method), Python performs "name mangling". It automatically changes the name of the method to include the class name, making it harder to access from outside the class. For example, if you have a class named MyClass, the method __private_method will be renamed to _MyClass__private_method.
Not Truly Private: While name mangling makes it less likely to accidentally access private methods from outside the class, it’s not a foolproof mechanism. Determined users could still access them if they really wanted to.
Error and exception handling
In Python, exceptions are events that occur during the execution of a program that disrupt the normal flow of the program. They can arise from various sources, such as:
- Runtime errors: Incorrect input, invalid operations, resource exhaustion, etc.
- Logical errors: Issues in the program’s logic that lead to unexpected behavior.
Error and Exception Handling in Python
In Python, exceptions are events that occur during the execution of a program that disrupt the normal flow of the program. They can arise from various sources, such as:
- Runtime errors: Incorrect input, invalid operations, resource exhaustion, etc.
- Logical errors: Issues in the program’s logic that lead to unexpected behavior.
Handling Exceptions with try...except
tryblock: Contains the code that might raise an exception.exceptblock: Contains the code that will be executed if an exception occurs. You can specify the type of exception to catch.elseblock: (Optional) Contains code that will be executed if no exceptions occur in thetryblock.finallyblock: (Optional) Contains code that will be executed regardless of whether an exception occurred or not.
try:
num1 = int(input("Enter the first number: "))
num2 = int(input("Enter the second number: "))
result = num1 / num2
print("Result:", result)
except ZeroDivisionError:
print("Error: Division by zero!")
except ValueError:
print("Error: Invalid input. Please enter numbers only.")
else:
print("Division successful.")
finally:
print("Execution complete.")Common Built-in Exceptions:
ZeroDivisionError: Raised when dividing by zero.ValueError: Raised when an operation or function receives an argument of an inappropriate type.TypeError: Raised when an operation or function is applied to an object of an inappropriate type.IndexError: Raised when trying to access a list or tuple index that is out of range.KeyError: Raised when trying to access a dictionary key that does not exist.
Raising Exceptions (Manually)
You can raise exceptions manually using the raise keyword:
if age < 0:
raise ValueError("Age cannot be negative.")Modules and Packages
Modules
What is a Module?
- A Python module is a single file containing Python code (functions, classes, variables, etc.).
- It allows you to organize your code into reusable units.
- Example:
mathmodule (for mathematical functions likesin,cos,sqrt),randommodule (for generating random numbers)
Importing Modules
Use the import statement to bring the module into your current script.
import math
result = math.sqrt(25)
print(result) # Output: 5.0Import specific functions/classes:
from math import sqrt, pi
result = sqrt(16)
print(pi)Import with an alias:
import math as m
result = m.sin(math.pi/2)
print(result)Packages
What is a Package?
- A package is a collection of related modules organized in a directory.
- It helps to structure large projects and avoid namespace conflicts.
- A package directory must contain a special file named
__init__.py(can be empty).
Importing from Packages:
import my_package.my_module
my_package.my_module.my_function()We can also import as below.
from my_package import my_modulefrom my_package.my_module import my_function
__name__ variable: This special variable holds the name of the current module. It's often used to determine if a script is being run directly or imported as a module:
Following is example of module.
# my_math_module.py
def add(x, y):
"""
This function adds two numbers.
Args:
x: The first number.
y: The second number.
Returns:
The sum of x and y.
"""
return x + y
def subtract(x, y):
"""
This function subtracts the second number from the first.
Args:
x: The first number.
y: The second number.
Returns:
The difference of x and y.
"""
return x - yUse this module
import my_math_module
result1 = my_math_module.add(5, 3) # Result: 8
result2 = my_math_module.subtract(5, 3) # Result: 2
print(result1)
print(result2)import module from different directory
Use sys.path.append()This method adds the directory containing the module to Python’s search path.
import sys
sys.path.append('/path/to/your/module/directory')
import your_moduleUsing PYTHONPATH Environment Variable. This method permanently adds the directory to Python’s search path.
export PYTHONPATH="$PYTHONPATH:/path/to/your/module/directory"Using Relative Imports (for packages): If your module is part of a package, you can use relative imports.
from . import my_module # Import from the same directory
from ..sub_package import my_module # Import from the parent directorystring
In Python, a string is a sequence of characters enclosed within either single quotes (') or double quotes (").
my_string1 = "This is a string."
my_string2 = 'Another string.'Accessing Characters:
- Strings are indexed, starting from 0.
- You can access individual characters using square brackets
[].
my_string = "Hello"
first_char = my_string[0] # Accesses the first character ('H')
last_char = my_string[-1] # Accesses the last character ('o')Slicing Strings:
my_string = "Python is awesome!"
substring = my_string[7:11] # Extracts "is aw"String Concatenation:
first_name = "John"
last_name = "Doe"
full_name = first_name + " " + last_name # Result: "John Doe"String Methods:
Python provides many built-in methods for string manipulation:
upper(): Converts the string to uppercase.lower(): Converts the string to lowercase.strip(): Removes leading and trailing whitespace.split(): Splits the string into a list of substrings.replace(): Replaces occurrences of one substring with another.find(): Returns the index of the first occurrence of a substring.- and many more!
my_string = "Hello, world!"
print(my_string.upper()) # Output: HELLO, WORLD!
print(my_string.lower()) # Output: hello, world!
my_string = " Hello "
print(my_string) # Output: Hello
print(my_string.strip()) # Output: Hello
sentence = "This is a sentence."
words = sentence.split() # Splits by whitespace by default
print(words) # Output: ['This', 'is', 'a', 'sentence.']
words = sentence.split(' ') # Explicitly split by spaces
print(words) # Output: ['This', 'is', 'a', 'sentence.']
text = "Hello, world!"
new_text = text.replace("world", "everyone")
print(new_text) # Output: Hello, everyone!
text = "Python is awesome!"
index = text.find("is")
print(index) # Output: 7 (index of the first occurrence of "is")
words = ["This", "is", "a", "list", "of", "words"]
sentence = " ".join(words)
print(sentence) # Output: This is a list of words
text = "This is a test string."
count_of_is = text.count("is")
print(count_of_is) # Output: 2String Formatting:
Use f-strings (formatted string literals) for easy string interpolation.
name = "Alice"
age = 30
message = f"Hello, {name}! You are {age} years old."Happy learning python!!!








