List
A list in is an ordered, mutable (changeable) collection of elements. Lists can hold
items of any type, including integers, strings, and other lists. They are defined
using square brackets [], with elements separated by commas.
Common List Operations:
Creating a List
A list can be created by simply enclosing the elements in square brackets.
my_list = [element1, element2, element3, ...]
Example:
numbers = [5, 10, 15, 20, 25, 30, 35]
Accessing Elements
List elements can be accessed using their index, starting from 0 for the first
element.
first_element = my_list[0] # Accesses the first element
last_element = my_list[-1] # Accesses the last element
Adding Elements
You can add new elements to a list using different methods:
○ append() adds an element to the end of the list.
○ insert() allows inserting an element at a specific position.
○ extend()Adds all elements of an iterable (like another list) to the end
of the list.
Example:
my_list.append(40) # Adds 40 at the end
my_list.insert(2, 12) # Inserts 12 at index 2
my_list.extend([50, 60])
Removing Elements
Elements can be removed from a list using:
○ remove(value) removes the first occurrence of a value.
○ pop(index) removes and returns the element at the given index (if no
index is specified, it removes the last element).
Example:
my_list.remove(20) # Removes the first occurrence of 20
my_list.pop(3) # Removes the element at index 3
Slicing a List
Slicing allows you to create a new list from a part of the original list.
The syntax for slicing is list[start:end], where start is inclusive and end is
exclusive.
sublist = my_list[1:4] # Retrieves elements from index 1 to 3
Finding the Sum and Average of Elements
○ sum() gives the sum of the list elements.
○ To find the average, divide the sum by the number of elements using
len().
Example:
total = sum(my_list)
average = total / len(my_list)
Counting Occurrences
You can count how many times a specific element appears in the list using count().
occurrences = my_list.count(15) # Counts how many times 15 appears in the list
Finding Maximum and Minimum
Use max() and min() to find the largest and smallest element in a list, respectively.
largest = max(my_list)
smallest = min(my_list)
Sorting Lists
○ The sort() method sorts a list in ascending order by default.
○ To sort in descending order, you can use the reverse=True argument.
Example:
my_list.sort() # Sorts in ascending order
my_list.sort(reverse=True) # Sorts in descending order
Reversing a List
The reverse() method reverses the order of elements in the list.
my_list.reverse() # Reverses the list
Removing Duplicates
Lists can contain duplicate elements. To remove duplicates, you can convert the list
into a set and then back into a list (sets do not allow duplicates).
my_list = list(set(my_list))
Cloning a List
You can create a copy of a list using the copy() method or by slicing.
cloned_list = my_list.copy() # Clones the list
# or
cloned_list = my_list[:] # Another way to clone
Checking if an Element Exists
The in keyword checks if an element is present in a list.
if 10 in my_list:
print("10 is in the list")
Clearing All Elements from the List
To remove all elements from the list, you can use the clear() method.
my_list.clear() # Empties the list
List Length
Use the len() function to get the number of elements in a list.
length = len(my_list) # Returns the length of the list
Nested Lists
Lists can contain other lists (nested lists). To access elements in nested lists, use
multiple indices.
nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
element = nested_list[1][2] # Accesses the element '6'
index()
Returns the index of the first occurrence of a specified value. Raises a ValueError
if the value is not found.
index_of_15 = my_list.index(15)
List Comprehension in Python
List comprehension is a concise way to create lists in Python. It allows you to
generate a new list by applying an expression to each element of an existing
iterable (like a list, tuple, or range). List comprehensions are typically more
readable and efficient than using traditional for loops.
General Syntax of List Comprehension
new_list = [expression for item in iterable if condition]
● expression: This is the value that will be added to the new list (it could be an
operation on the item).
● item: The variable that represents each element in the iterable.
● iterable: The collection you are iterating over (list, tuple, range, etc.).
● condition (optional): A condition to filter which items to include in the new
list. The expression is only evaluated if the condition is True.
Examples of List Comprehension
Creating a List of Squares
Using a for loop:
squares = []
for i in range(10):
squares.append(i**2)
Using list comprehension:
squares = [i**2 for i in range(10)]
print(squares) # Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Benefits of List Comprehension:
1. Concise and Readable: List comprehensions reduce the amount of code
needed to create or manipulate a list.
2. Efficiency: In many cases, list comprehensions can be more efficient than
using a regular for loop because they are optimized for list creation.
3. Flexibility: You can easily apply transformations or filters while iterating
over a list in a single line of code.
List Aliasing in Python
List aliasing refers to the situation where multiple variables point to the same list
object in memory. This can lead to unexpected behavior because changes made to
one list will be reflected in all variables that are referencing that same list. It is
important to understand how list aliasing works, especially when dealing with
mutable objects like lists.
What is Aliasing?
In Python, variables are just labels (or references) to objects in memory. When you
assign a list to another variable, both variables point to the same list (object), not
a copy of it. This is known as aliasing.
Example of List Aliasing
# Create a list
original_list = [1, 2, 3, 4]
# Create an alias to the original list
alias_list = original_list
# Modify the alias list
alias_list.append(5)
# Both lists are affected because they refer to the same object
print("Original List:", original_list) # Output: [1, 2, 3, 4, 5]
print("Alias List:", alias_list) # Output: [1, 2, 3, 4, 5]
In this example:
● original_list and alias_list both refer to the same list object in memory.
● When we modify alias_list by appending 5, the change is reflected in
original_list as well because they are linked to the same object.
Why Does Aliasing Happen?
In Python, when you assign one list to another, you are not creating a copy. Instead,
both variables point to the same list object. This is because lists are mutable,
meaning their contents can be changed, and they are assigned by reference, not by
value.
alias_list = original_list # Both variables refer to the same list in memory
Effects of List Aliasing
Mutating the List Affects All Aliases: Any changes (additions, deletions,
modifications) to one of the lists will affect all references (aliases) to that list.
original_list[0] = 100
print(alias_list) # Output: [100, 2, 3, 4, 5]
Memory Sharing: Since both variables point to the same list object, only one list
exists in memory. This can save memory, but it also means you need to be cautious
when modifying the list.
Tuple Operations in Python
Tuples are one of the fundamental data types in Python. They are similar to lists
but with one key difference: tuples are immutable, meaning once created, their
elements cannot be modified. They are often used to store collections of
heterogeneous data (data of different types) and are useful when the integrity of
data needs to be maintained.
Below is a general overview of the various operations and concepts related to
tuples in Python.
1. Creating a Tuple
Tuples are created by placing values inside parentheses (), separated by commas.
Tuples can contain elements of different data types, including other tuples, lists, or
dictionaries.
# Creating a tuple
my_tuple = (1, 2, 3)
another_tuple = ("apple", 3.5, [1, 2, 3])
A tuple with a single element must include a trailing comma:
single_element_tuple = (5,)
2. Accessing Elements in a Tuple
You can access elements in a tuple using indexing. Python uses zero-based
indexing, so the first element is at index 0, the second at index 1, and so on.
# Accessing elements by index
my_tuple = ("John Doe", 22, "Computer Science", 85, 90, 88)
print(my_tuple[0]) # Output: John Doe
print(my_tuple[1]) # Output: 22
Negative Indexing is also supported, which allows you to access elements starting
from the end of the tuple.
# Negative indexing
print(my_tuple[-1]) # Output: 88 (Last element)
print(my_tuple[-2]) # Output: 90 (Second last element)
3. Slicing a Tuple
Just like lists, you can slice a tuple to extract a part of it. Slicing returns a new tuple
containing the elements from the specified start index to the stop index (exclusive).
# Slicing a tuple
sliced_tuple = my_tuple[1:4] # Elements from index 1 to 3
print(sliced_tuple) # Output: (22, 'Computer Science', 85)
4. Concatenation and Repetition
● Concatenation: You can concatenate two or more tuples using the +
operator. This creates a new tuple by joining the elements of the original
tuples.
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
result = tuple1 + tuple2
print(result) # Output: (1, 2, 3, 4, 5, 6)
● Repetition: You can repeat the elements of a tuple using the * operator.
tuple1 = (1, 2)
repeated = tuple1 * 3
print(repeated) # Output: (1, 2, 1, 2, 1, 2)
5. Tuple Unpacking
Tuple unpacking allows you to assign the individual elements of a tuple to
variables in a single statement. This is very useful when you want to extract values
directly from a tuple.
# Tuple unpacking
student = ("John Doe", 22, "Computer Science", 85, 90, 88)
name, age, major, *grades = student
print(name) # Output: John Doe
print(age) # Output: 22
print(major) # Output: Computer Science
print(grades) # Output: [85, 90, 88]
In the above example, the first three elements are unpacked into name, age, and
major, while the remaining elements (grades) are collected into a list.
6. Immutability and Modifying Tuples
Tuples are immutable, meaning you cannot modify their elements directly. If you
need to modify the contents of a tuple, you would need to:
1. Convert the tuple to a list.
2. Modify the list.
3. Convert the list back into a tuple.
Example: Changing the student's age.
# Converting tuple to list and modifying
student = ("John Doe", 22, "Computer Science", 85, 90, 88)
student_list = list(student) # Convert tuple to list
student_list[1] = 23 # Modify age
student = tuple(student_list) # Convert list back to tuple
print(student) # Output: ('John Doe', 23, 'Computer Science', 85, 90, 88)
7. Adding Elements to a Tuple
Since tuples are immutable, you cannot add elements directly. However, you can:
● Convert the tuple to a list.
● Append the new element to the list.
● Convert the list back to a tuple.
# Adding a new element
student_list = list(student)
student_list.append("Senior")
student = tuple(student_list)
print(student) # Output: ('John Doe', 23, 'Computer Science', 85, 90, 88, 'Senior')
8. Checking for Existence
You can check if an element exists in a tuple using the in operator.
# Checking for an element
print("Computer Science" in student) # Output: True
print("Math" in student) # Output: False
9. Calculating Average of Elements in Tuple
If the tuple contains numerical values (e.g., grades), you can calculate the average
by extracting the relevant elements and applying basic arithmetic.
# Calculate average of grades (last three elements in the tuple)
grades = student[3:] # Extract grades
average = sum(grades) / len(grades)
print("Average Grade:", average) # Output: Average Grade: 87.66666666666667
10. Negative Indexing and Retrieving Last Element
You can retrieve the last element of a tuple using negative indexing. The index -1
refers to the last element, -2 refers to the second last, and so on.
# Retrieve the last element
print(student[-1]) # Output: Senior
11. Tuple Packing
Tuple packing is when you assign multiple values into a tuple directly. This is
typically done when you want to return multiple values from a function or store
multiple values in a tuple.
# Tuple packing
person = ("Alice", 25, "Engineer")
Sets in Python
A set is a built-in data type in Python that represents an unordered collection of
unique elements. Sets are widely used when you need to perform operations such
as membership testing, eliminating duplicates, and mathematical set operations like
intersection, union, and difference.
Key Characteristics of Sets:
1. Unordered: The elements in a set do not have a specific order. This means that
there is no indexing or slicing available like in lists or tuples.
2. Unique: Sets do not allow duplicate elements. If you try to add a duplicate,
it will be ignored.
3. Mutable: Sets can be modified after creation. You can add or remove
elements from a set.
4. No Indexing or Slicing: Since sets are unordered, you cannot access
elements using an index or slice notation.
5. Dynamic: Sets can grow and shrink in size as elements are added or
removed.
Operations on Sets
Creating a Set: Sets are created using curly braces {} or the set() constructor.
my_set = {1, 2, 3, 4}
another_set = set([1, 2, 3, 4])
Adding Elements: You can add a single element to a set using the add() method.
my_set.add(5) # Adds 5 to the set
Removing Elements: You can remove an element from a set using the remove()
method. If the element is not found, it raises a KeyError. You can also use discard()
which does not raise an error if the element is not present.
my_set.remove(3) # Removes 3 from the set
my_set.discard(10) # Does not raise error if 10 is not in the set
Set Operations:
Union (| or .union()): Combines two sets and returns all unique elements.
set1 = {1, 2, 3}
set2 = {3, 4, 5}
result = set1 | set2 # Result: {1, 2, 3, 4, 5}
Intersection (& or .intersection()): Returns a set containing only the elements
present in both sets.
result = set1 & set2 # Result: {3}
Difference (- or .difference()): Returns a set containing elements that are in the
first set but not in the second.
result = set1 - set2 # Result: {1, 2}
Symmetric Difference (^ or .symmetric_difference()): Returns a set containing
elements that are in either of the sets, but not both.
result = set1 ^ set2 # Result: {1, 2, 4, 5}
Membership Testing: You can check if an element exists in a set using the in
keyword.
2 in my_set # Returns True
5 in my_set # Returns False
Set Length: You can get the number of elements in a set using the len() function.
len(my_set) # Returns the number of elements in my_set
Clearing a Set: The clear() method removes all elements from a set.
my_set.clear() # Clears all elements from my_set
Deleting a Set: The del keyword can be used to delete a set entirely.
del my_set # Deletes my_set
Why Duplicates Are Removed in a Set
In sets, duplicates are automatically removed because the core idea of a set is that
it only holds unique elements. When you try to add an element that is already
present, it will simply be ignored.
my_set = {1, 2, 3, 3, 4}
print(my_set) # Output: {1, 2, 3, 4}
In the above example, the duplicate 3 is ignored when the set is created.
Frozensets in Python
A frozenset is a variant of a set, but it is immutable. This means that once a
frozenset is created, its elements cannot be changed, added, or removed. Frozensets
are hashable, which allows them to be used as keys in dictionaries and elements of
other sets.
Key Characteristics of Frozensets:
1. Immutable: Once created, frozensets cannot be modified (i.e., no adding,
removing, or updating elements).
2. Hashable: Because frozensets are immutable, they are hashable and can be
used as dictionary keys or elements of other sets.
3. Supports Set Operations: You can perform operations like union,
intersection, and difference on frozensets.
Creating a Frozenset:
A frozenset is created using the frozenset() constructor:
frozen_set = frozenset([1, 2, 3])
Example Operations on Frozensets:
Union: Combines two frozensets.
frozenset1 = frozenset([1, 2, 3])
frozenset2 = frozenset([3, 4, 5])
result = frozenset1 | frozenset2 # Result: frozenset({1, 2, 3, 4, 5})
Intersection: Finds common elements between frozensets.
result = frozenset1 & frozenset2 # Result: frozenset({3})
Difference: Finds elements present in the first frozenset but not in the second.
result = frozenset1 - frozenset2 # Result: frozenset({1, 2})
Symmetric Difference: Finds elements that are in either of the two frozensets but
not in both.
result = frozenset1 ^ frozenset2 # Result: frozenset({1, 2, 4, 5})
Dictionaries in Python
A dictionary in Python is an unordered collection of key-value pairs. Each
element in a dictionary is a pair consisting of a unique key and its associated value.
Dictionaries are also referred to as associative arrays or hashmaps in other
programming languages.
Key Characteristics of a Dictionary:
1. Unordered: Unlike lists ortuples, dictionaries do not guarantee any order of
elements. In Python 3.7+, dictionaries maintain the insertion order of keys,
but this behavior should not be relied upon for logic, as dictionaries are
designed to be unordered.
2. Mutable: Dictionaries are mutable, meaning that you can modify their
contents after creation (i.e., add, remove, or update items).
3. Key-Value Pairs: Each dictionary element consists of a key and a
corresponding value. The key is unique, and it is used to access the value
associated with it.
4. Key Uniqueness: Keys in a dictionary must be unique. If a duplicate key is
added, the previous value associated with that key is overwritten.
5. Immutability of Keys: The keys in a dictionary must be of an immutable
type (such as strings, numbers, or tuples). The values, on the other hand, can
be of any data type.
6. Efficient Lookup: Dictionaries are optimized for fast lookups. The time
complexity for retrieving a value by key is O(1) on average.
Basic Operations on Dictionaries
Creating a Dictionary: Dictionaries can be created using curly braces {} or the
dict() constructor.
my_dict = {"name": "John", "age": 30, "city": "New York"}
another_dict = dict(key1="value1", key2="value2")
Accessing Values: To access a value in a dictionary, use the key inside square
brackets or use the get() method.
age = my_dict["age"]
city = my_dict.get("city") # safer as it returns None if key is not found
Adding/Updating Key-Value Pairs: You can add a new key-value pair or update
an existing value by specifying the key.
my_dict["occupation"] = "Engineer" # Adds a new key-value pair
my_dict["age"] = 31 # Updates the value for the existing key "age"
Deleting Items: You can remove an item from a dictionary using the del keyword
or the pop() method.
del my_dict["age"] # Removes the key "age" and its value
value = my_dict.pop("city") # Removes the key "city" and returns its value
Checking if a Key Exists: You can check if a key exists in the dictionary using the
in operator.
if "name" in my_dict:
print("Name is present")
Iterating Over a Dictionary: You can iterate over the keys, values, or both keys
and values of a dictionary.
# Iterating over keys
for key in my_dict:
print(key)
# Iterating over values
for value in my_dict.values():
print(value)
# Iterating over key-value pairs
for key, value in my_dict.items():
print(f"{key}: {value}")
Getting the Number of Items: Use the len() function to get the number of
key-value pairs in a dictionary.
length = len(my_dict)
Copying a Dictionary: To create a shallow copy of a dictionary, use the copy()
method.
copy_dict = my_dict.copy()
Clearing a Dictionary: You can remove all key-value pairs from a dictionary
using the clear() method.
my_dict.clear()
Advanced Operations on Dictionaries
Nested Dictionaries: Dictionaries can contain other dictionaries as values, which
is known as nesting. This is useful when you need to store complex data.
nested_dict = {"student1": {"name": "John", "age": 25}, "student2": {"name":
"Alice", "age": 22}}
print(nested_dict["student1"]["name"]) # Output: John
Default Values with get(): The get() method allows you to provide a default value
if the key is not found.
print(my_dict.get("occupation", "Not Available")) # Output: Not Available
Merging Two Dictionaries: You can merge dictionaries using the update() method
or the unpacking operator ** in Python 3.5+.
dict1 = {"name": "Alice", "age": 25}
dict2 = {"city": "London", "country": "UK"}
dict1.update(dict2) # Merges dict2 into dict1
# Or using the ** operator
merged_dict = {**dict1, **dict2}
Finding Keys with Maximum/Minimum Values: You can use max() or min() to
find the key associated with the maximum or minimum value in the dictionary.
max_key = max(my_dict, key=my_dict.get) # Finds the key with the maximum
value
min_key = min(my_dict, key=my_dict.get) # Finds the key with the minimum
value
Dictionary Comprehensions: You can create dictionaries in a compact way using
dictionary comprehensions.
squares = {x: x**2 for x in range(1, 6)} # Creates a dictionary of squares
Why Use a Dictionary?
1. Efficient Lookups: Dictionaries provide constant time complexity (O(1))
for key-based lookups, making them far more efficient than searching
through lists (O(n)) or tuples.
2. Key-Value Pair: Dictionaries allow for more flexible data management,
where each key is mapped to a value. This is useful for situations where you
need to store associations like mappings, configurations, etc.
3. Avoiding Duplicates: Unlike lists, dictionaries automatically prevent
duplicate keys. If a duplicate key is added, it simply overwrites the existing
value, making them ideal for scenarios where uniqueness is important.
4. Mutable and Flexible: Dictionaries are mutable, allowing you to easily add,
modify, or remove key-value pairs. This is more flexible than immutable
structures like tuples.
5. Better Alternative to Lists/Tuples: While lists and tuples store elements in
an ordered collection, dictionaries are designed for situations where fast
access and unique associations are needed.
UNIT V
What is a File in Python?
In Python, a file is a collection of data stored in a specific location on your disk.
Files can be opened, read, written to, and manipulated using various built-in
functions and methods. Python provides a powerful way to interact with files using
file objects.
File Types
In Python, files can be categorized into various types based on their contents:
1. Text Files: These files contain human-readable characters (letters, numbers,
symbols) and can be opened as text. The default encoding for text files is
usually UTF-8.
○ Example: .txt, .csv, .html
2. Binary Files: These files contain data that is not readable as text (e.g.,
images, videos, executable files, etc.). These files are typically opened in
binary mode.
○ Example: .jpg, .png, .exe, .pdf
File Modes
When opening a file, you need to specify the mode that determines the operation
you want to perform on the file. The following are common file modes in Python:
'r' (Read): Opens the file for reading. The file pointer is placed at the beginning of
the file. If the file doesn't exist, it raises a FileNotFoundError.
file = open('example.txt', 'r')
'w' (Write): Opens the file for writing. If the file exists, it truncates (removes) the
file. If the file doesn't exist, a new file is created.
file = open('example.txt', 'w')
'a' (Append): Opens the file for appending. If the file exists, data will be written to
the end of the file. If the file doesn't exist, a new file is created.
file = open('example.txt', 'a')
'b' (Binary): This mode is used along with other modes ('rb', 'wb', 'ab') to read,
write, or append in binary mode.
file = open('image.jpg', 'rb')
'x' (Exclusive Creation): This mode creates a new file. If the file already exists, it
raises a FileExistsError.
file = open('new_file.txt', 'x')
'r+' (Read and Write): Opens the file for both reading and writing. The file
pointer is placed at the beginning of the file.
file = open('example.txt', 'r+')
'w+' (Write and Read): Opens the file for both writing and reading. If the file
exists, it truncates the file.
file = open('example.txt', 'w+')
'a+' (Append and Read): Opens the file for both appending and reading. If the file
exists, data will be appended to the file.
file = open('example.txt', 'a+')
File Methods
Python provides various methods to interact with files. These methods are
available after you open the file using the open() function.
file.read(size=-1): Reads the entire file or a specified number of bytes. If the size is
omitted or negative, it reads the entire file.
content = file.read()
file.readline(): Reads a single line from the file.
line = file.readline()
file.readlines(): Reads all lines of a file into a list.
lines = file.readlines()
file.write(string): Writes the string to the file. It returns the number of characters
written.
file.write("Hello, World!")
file.writelines(lines): Writes a list of lines to the file. Each item in the list is
written as a separate line.
file.writelines(["First line\n", "Second line\n"])
file.seek(offset, whence=0): Moves the file pointer to the given offset position.
You can specify the reference position using whence (0: beginning, 1: current
position, 2: end).
file.seek(0)
file.tell(): Returns the current position of the file pointer.
position = file.tell()
file.flush(): Forces the write buffer to be flushed to the file. This can be useful to
ensure that data is written to the disk.
file.flush()
file.close(): Closes the file and frees up system resources.
file.close()
Format Operators
In Python, file handling is a crucial concept for reading from and writing to files.
Alongside basic file operations, formatting is frequently used when reading from
or writing to files, especially when data needs to be presented in a structured way.
This is where format operators (like %, .format(), and f-strings) come into play to
dynamically format the data being written to or read from files.
Here’s an explanation of how format operators are used in file operations and
how they help in structuring data.
Format Operators in File Writing and Reading
Using % Operator in File Operations
The % operator can be used in file operations for formatting the output when
writing structured data to a file or formatting content read from a file.
Writing to a File with the % Operator:
You can use the % operator to insert data into a formatted string and then write it to
a file.
# Open file for writing
file = open("employee_data.txt", "w")
# Employee data
name = "Alice"
age = 30
salary = 50000
# Using % operator to format the string
file.write("Employee: %s, Age: %d, Salary: $%.2f\n" % (name, age, salary))
# Close the file
file.close()
Reading from a File with the % Operator:
You can read data from a file and use the % operator to display it in a structured
format.
# Open file for reading
file = open("employee_data.txt", "r")
# Read the line
line = file.readline()
# Format and display the data
name, age, salary = line.strip().split(", ")
age = int(age.split(":")[1].strip())
salary = float(salary.split(":")[1].strip().replace("$", ""))
# Using % operator to format the output
print("Name: %s, Age: %d, Salary: $%.2f" % (name.split(":")[1].strip(), age,
salary))
# Close the file
file.close()
Using .format() in File Operations
The .format() method is another powerful tool for string formatting and can be
used in both reading and writing files to generate structured data.
Writing to a File with .format():
# Open file for writing
file = open("employee_data.txt", "w")
# Employee data
name = "Bob"
age = 28
salary = 60000
# Using .format() to format the string
file.write("Employee: {}, Age: {}, Salary: ${:.2f}\n".format(name, age, salary))
# Close the file
file.close()
Reading from a File with .format():
After reading the content, .format() can be used to display the formatted content.
# Open file for reading
file = open("employee_data.txt", "r")
# Read the line
line = file.readline()
# Split and format
name, age, salary = line.strip().split(", ")
age = int(age.split(":")[1].strip())
salary = float(salary.split(":")[1].strip().replace("$", ""))
# Using .format() to format the output
print("Name: {}, Age: {}, Salary: ${:.2f}".format(name.split(":")[1].strip(), age,
salary))
# Close the file
file.close()
Using f-strings in File Operations
f-strings (formatted string literals) are the most modern and efficient way to
format strings in Python. They can be used in both writing to and reading from
files, making the code cleaner and more readable.
Writing to a File with f-strings:
# Open file for writing
file = open("employee_data.txt", "w")
# Employee data
name = "Charlie"
age = 35
salary = 70000
# Using f-string to format the string
file.write(f"Employee: {name}, Age: {age}, Salary: ${salary:.2f}\n")
# Close the file
file.close()
Reading from a File with f-strings:
When reading from the file, you can use f-strings to format the data and display it.
# Open file for reading
file = open("employee_data.txt", "r")
# Read the line
line = file.readline()
# Split and format
name, age, salary = line.strip().split(", ")
age = int(age.split(":")[1].strip())
salary = float(salary.split(":")[1].strip().replace("$", ""))
# Using f-string to format the output
print(f"Name: {name.split(':')[1].strip()}, Age: {age}, Salary: ${salary:.2f}")
# Close the file
file.close()
Command Line Arguments in Python
Command line arguments are values that you pass to a Python program when you
execute it from the terminal or command prompt. They are passed after the name
of the script and are accessible within the script.
For example:
python script.py arg1 arg2 arg3
Here, script.py is the Python script, and arg1, arg2, arg3 are the command line
arguments passed to the script.
Accessing Command Line Arguments in Python
To work with command line arguments, Python provides a built-in module called
sys. This module contains the list sys.argv that holds the command line arguments
passed to the script.
● sys.argv is a list in which:
○ The first element sys.argv[0] is always the name of the Python script.
○ The subsequent elements sys.argv[1:] are the arguments passed to the
script.
Basic Usage of sys.argv
Here's how you can use sys.argv to handle command line arguments:
Example: Accessing Command Line Arguments
import sys
# sys.argv is a list, where the first element is the script name
print("Script Name:", sys.argv[0]) # Prints the name of the Python script
# Access command line arguments passed to the script
for i in range(1, len(sys.argv)):
print(f"Argument {i}:", sys.argv[i])
Running the script:
python script.py arg1 arg2 arg3
Output:
Script Name: script.py
Argument 1: arg1
Argument 2: arg2
Argument 3: arg3
In this example, the script prints the name of the script followed by each of the
command line arguments.
Command Line Arguments as Input
You can use the command line arguments to input values into your program,
making it more interactive and flexible. Let's look at an example where command
line arguments are used for addition.
Example: Command Line Arguments for Addition
import sys
# Check if there are enough arguments (at least 3 arguments)
if len(sys.argv) != 3:
print("Usage: python script.py <num1> <num2>")
else:
# Convert arguments to integers and perform addition
num1 = int(sys.argv[1])
num2 = int(sys.argv[2])
result = num1 + num2
print(f"The sum of {num1} and {num2} is {result}")
Running the script:
python script.py 5 10
Output:
The sum of 5 and 10 is 15
In this case, the program reads two numbers from the command line arguments,
adds them together, and prints the result.
Handling Different Types of Arguments
Command line arguments are passed as strings by default. If you want to use
numbers or other data types, you must convert them to the appropriate type (e.g.,
using int() for integers or float() for floating-point numbers).
Example: Handling Integers and Floats
import sys
# Convert arguments to the correct types
num1 = int(sys.argv[1]) # Convert first argument to integer
num2 = float(sys.argv[2]) # Convert second argument to float
# Perform arithmetic operation
result = num1 + num2
print(f"The result of {num1} + {num2} is {result}")
Running the script:
python script.py 5 10.5
Output:
The result of 5 + 10.5 is 15.5
Exception Handling in Python
An exception is an event that occurs during the execution of a program, which
disrupts the normal flow of the program's instructions. Exceptions can be caused
by many factors, such as:
● Trying to divide by zero.
● Accessing a file that doesn't exist.
● Trying to use a variable that is not defined.
● Providing invalid input data.
When an exception occurs, Python stops the current execution and looks for an
exception handler to deal with it. If no handler is found, the program crashes.
Basic Structure of Exception Handling
Python uses try, except, else, and finally blocks to handle exceptions.
Syntax:
try:
# Code that may raise an exception
except SomeException as e:
# Code that runs if the exception occurs
else:
# Code that runs if no exception occurs
finally:
# Code that runs no matter what (optional)
1. try block: The code that might raise an exception is placed here. If no
exception occurs, the code inside the except block is skipped.
2. except block: This block catches the exception and handles it. It runs when
an exception occurs in the try block.
3. else block: If no exception occurs in the try block, the else block is
executed.
4. finally block: This block runs regardless of whether an exception occurred
or not. It is usually used for cleanup actions (like closing a file).
Example of Exception Handling
try:
num1 = int(input("Enter a number: "))
num2 = int(input("Enter another number: "))
result = num1 / num2
print(f"The result of {num1} divided by {num2} is {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
except ValueError:
print("Error: Invalid input. Please enter a valid number.")
else:
print("Division performed successfully.")
finally:
print("Execution completed.")
Explanation:
● In the try block, the program attempts to take two numbers from the user and
divide them.
● If the user enters a non-integer value, a ValueError will occur.
● If the user tries to divide by zero, a ZeroDivisionError will occur.
● The else block runs only if no exception occurs.
● The finally block will always run, regardless of whether an exception occurs
or not.
Common Exception Types in Python
● ZeroDivisionError: Raised when dividing by zero.
● ValueError: Raised when a function receives an argument of the right type
but inappropriate value (e.g., invalid number format).
● IndexError: Raised when trying to access an index that is out of range for a
list or tuple.
● KeyError: Raised when trying to access a dictionary with a key that does
not exist.
● FileNotFoundError: Raised when trying to open a file that doesn't exist.
● TypeError: Raised when an operation or function is applied to an object of
inappropriate type.
● NameError: Raised when a local or global name is not found.
Example: KeyError
my_dict = {'name': 'Alice', 'age': 25}
try:
print(my_dict['address'])
except KeyError:
print("Error: The key 'address' does not exist in the dictionary.")
Catching Multiple Exceptions
You can catch multiple exceptions in a single except block by specifying a tuple of
exception types.
try:
value = int(input("Enter a number: "))
result = 10 / value
except (ValueError, ZeroDivisionError) as e:
print(f"Error: {e}")
In this example, both ValueError (if the input is not a valid integer) and
ZeroDivisionError (if the user tries to divide by zero) are handled in the same
except block.
Accessing Exception Details
When an exception is caught, you can access its details (such as the error message)
using the as keyword. The error message can be printed or logged for debugging
purposes.
try:
x=1/0
except ZeroDivisionError as e:
print(f"An error occurred: {e}")
This will output:
An error occurred: division by zero
Raising Exceptions
Sometimes, you may want to raise an exception intentionally in your code to
indicate an error. This is done using the raise statement.
Example: Raising an Exception
def check_age(age):
if age < 18:
raise ValueError("Age must be at least 18.")
return age
try:
age = int(input("Enter your age: "))
check_age(age)
except ValueError as e:
print(f"Error: {e}")
In this example, the check_age() function raises a ValueError if the age is less than
18.
Custom Exceptions
You can define your own exceptions by creating a new class that inherits from the
built-in Exception class.
Example: Custom Exception
class NegativeAgeError(Exception):
pass
def check_age(age):
if age < 0:
raise NegativeAgeError("Age cannot be negative.")
return age
try:
age = int(input("Enter your age: "))
check_age(age)
except NegativeAgeError as e:
print(f"Error: {e}")
In this example, we define a custom exception NegativeAgeError to raise an error
when a negative age is entered.
The else and finally Blocks
● else block: This block is executed if no exception occurs in the try block.
● finally block: This block is always executed, no matter what, and is
generally used for cleanup operations like closing files or releasing
resources.
Example: Using else and finally
try:
file = open('data.txt', 'r')
data = file.read()
except FileNotFoundError:
print("Error: File not found.")
else:
print("File read successfully.")
print(data)
finally:
print("Closing the file.")
file.close()
In this example:
● The else block is executed only if the file is opened and read successfully.
● The finally block ensures that the file is closed, whether an exception occurs
or not.
Modules and Packages in Python
A module is a single file (with a .py extension) that contains Python code. It can
define functions, classes, variables, and runnable code. Modules help in organizing
related functions and variables in a single file, which can be imported and used in
other Python programs.
How to Create a Module
A module is simply a Python file that contains code. For example, let's create a
module math_operations.py:
# math_operations.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
Importing a Module
Once you have a module, you can import it into your Python script using the
import statement.
# Importing the math_operations module
import math_operations
# Using functions from the math_operations module
result_add = math_operations.add(3, 5)
result_sub = math_operations.subtract(10, 4)
print(f"Addition: {result_add}")
print(f"Subtraction: {result_sub}")
Importing Specific Functions or Variables
If you only need a specific function or variable from a module, you can import it
directly using the from keyword.
# Importing specific functions
from math_operations import add
# Using the 'add' function directly
result = add(7, 3)
print(f"Addition: {result}")
Renaming Imported Modules or Functions
You can also alias a module or function using the as keyword.
# Importing and renaming the module
import math_operations as mo
# Using the alias to call functions
result = mo.add(4, 6)
print(f"Addition: {result}")
What is a Package in Python?
A package is a collection of Python modules. It is a directory containing multiple
Python module files (each having a .py extension) and an __init__.py file that is
executed when the package is imported. The __init__.py file can be empty, or it
can contain initialization code for the package.
Packages help in organizing modules into submodules, and they can be nested
inside other packages (known as sub-packages).
Creating a Package
Let’s create a simple package with two modules: math_operations.py and
string_operations.py.
Directory structure for a package:
my_package/
├── __init__.py # Marks the directory as a package
├── math_operations.py # Module 1: Contains math-related functions
└── string_operations.py # Module 2: Contains string-related functions
1. math_operations.py:
# my_package/math_operations.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
2. string_operations.py:
# my_package/string_operations.py
def concatenate(str1, str2):
return str1 + str2
def capitalize(str1):
return str1.capitalize()
3. __init__.py:
# my_package/__init__.py
# This file can be empty or contain initialization code
Importing from a Package
To use a package, you can import modules from it in the same way you import a
module.
# Importing a module from a package
import my_package.math_operations
# Using functions from the math_operations module
result_add = my_package.math_operations.add(10, 5)
result_sub = my_package.math_operations.subtract(20, 8)
print(f"Addition: {result_add}")
print(f"Subtraction: {result_sub}")
Alternatively, you can import specific functions or even alias them:
# Importing specific functions from a module inside the package
from my_package.math_operations import add
#Using the 'add' function directly
result = add(3, 4)
print(f"Addition: {result}")
You can also import the entire package using the import statement:
# Importing the entire package
import my_package
# Accessing functions via the package name
result = my_package.math_operations.add(7, 8)
print(f"Addition: {result}")
3. Standard Python Packages
Python comes with a standard library of packages that provide pre-built
functionality, such as:
● math: Provides mathematical functions like sqrt(), sin(), cos(), etc.
● os: Provides a way to interact with the operating system (file handling,
directory operations, etc.).
● sys: Provides access to command-line arguments and system-specific
parameters.
● random: Provides functions for generating random numbers.
● datetime: Provides classes for manipulating dates and times.
Example: Using a Standard Package (math)
import math
# Using the sqrt() function from the math module
result = math.sqrt(16)
print(f"Square root of 16 is {result}")
4. Importing from Nested Packages
Packages can also contain sub-packages, allowing you to organize your code into
multiple levels. Let’s create a nested package structure:
my_package/
├── __init__.py
├── math_operations/
│ ├── __init__.py
│ ├── add.py
│ └── subtract.py
└── string_operations/
├── __init__.py
└── concatenate.py
In this structure, we have two sub-packages inside the my_package package:
math_operations and string_operations.
Importing from a Nested Package
You can access the sub-package modules using dot notation:
# Importing from a sub-package
from my_package.math_operations import add
result = add.add(5, 3)
print(f"Addition: {result}")
5. Advantages of Modules and Packages
● Code Reusability: You can write code in one module and reuse it in other
scripts without duplicating the code.
● Code Organization: Packages allow you to organize related modules into
directories, making it easier to manage large codebases.
● Namespace Management: Modules and packages help in organizing
namespaces and avoiding naming conflicts between variables and functions.
● Easier Maintenance: By organizing code into modules and packages,
maintaining and updating the code becomes easier, as related functionality is
kept together.