0% found this document useful (0 votes)
5 views83 pages

DAP_2_module

The document provides an overview of strings in Python, detailing their characteristics as immutable sequences of characters and various methods for creating and manipulating them. It covers string operations such as concatenation, slicing, joining, and accessing characters by index, along with examples for clarity. Additionally, it explains the use of positive and negative indexing, error handling, and practical applications of string manipulation in programming.

Uploaded by

sharadhi080808
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views83 pages

DAP_2_module

The document provides an overview of strings in Python, detailing their characteristics as immutable sequences of characters and various methods for creating and manipulating them. It covers string operations such as concatenation, slicing, joining, and accessing characters by index, along with examples for clarity. Additionally, it explains the use of positive and negative indexing, error handling, and practical applications of string manipulation in programming.

Uploaded by

sharadhi080808
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 83

MODULE – 2

Strings in Python
In Python, a string is a sequence of characters, which can include letters, numbers,
punctuation marks, and spaces.

Strings are one of the most commonly used data types in Python and are immutable,
meaning their contents cannot be changed after creation.

Strings are used to represent text data and support a wide range of operations and
methods for manipulation

Creating and Storing Strings


Strings in Python can be created and stored in several ways, providing flexibility for different
use cases. Below are the primary methods for creating strings:

1. Using Single or Double Quotes

Strings can be enclosed in either single quotes (') or double quotes ("). Both are equivalent
in Python, allowing developers to choose based on convenience or to avoid escaping
certain characters.

• s1 = 'hello' # Using single quotes

• s2 = "world" # Using double quotes

• print(s1) # Output: hello

print(s2) # Output: world

2. Using Triple Quotes for Multi-line Strings

Triple quotes (''' or """) are used to create multi-line strings, which are useful for storing
paragraphs, documentation strings (docstrings), or formatted text.

• multi_line = """This is a multi-line

string that spans

across several lines."""

print(multi_line)
3. Raw Strings

Raw strings are created by prefixing a string literal with r or R. In raw strings, backslashes (\)
are treated as literal characters and not as escape characters. This is particularly useful for
regular expressions or file paths.

• raw_str = r"world health \n organization"

print(raw_str) # Output: world health \n organization

• Use Case: Raw strings are ideal for Windows file paths (e.g., r"C:\Users\Name") or
regex patterns where backslashes are common.

4. String as a Sequence

Strings are stored internally as a sequence of Unicode characters, allowing them to


support operations like indexing, slicing, and iteration. Each character in a string has an
associated index, starting from 0.

Basic String Operations


Python provides a variety of operations to manipulate strings. These operations allow
concatenation, checking for substrings, comparison, and traversal. Below are the key basic
string operations:

1. String Concatenation

Concatenation combines two or more strings into a single string. Python supports
concatenation using the + operator or by placing string literals side by side.

• Using the + Operator:

• str1 = "Hello"

• str2 = "there"

• str3 = str1 + str2

print(str3) # Output: Hellothere

• Side-by-Side Concatenation: When string literals are placed next to each other
without any operator, Python automatically concatenates them. This is less
common but useful for breaking long strings across lines.

• str4 = 'this' 'is' 'python' 'class'


print(str4) # Output: thisispythonclass

• Note: Concatenation using + creates a new string object, as strings are immutable.

2. The in Operator

The in operator is a Boolean operator that checks if one string (substring) is present within
another string. It returns True if the substring is found, otherwise False.

• if 'pa' in "roopa":

• print('Your string contains "pa".') # Output: Your string contains "pa".

• if ';' not in "roopa":

print('Your string does not contain any semicolons.') # Output: Your string does not
contain any semicolons.

• Use Case: The in operator simplifies checks for substrings, such as validating input
or searching for patterns. For :

• t = 'a'

• if t in 'aeiou':

print(f"{t} is a vowel.") # Output: a is a vowel.

3. String Comparison

Strings can be compared using standard comparison operators (<, >, ==, !=, <=, >=).
Comparisons are based on the ASCII or Unicode values of the characters, performed
character by character from left to right.

name = "Ravindra"

word = "Anil"

if name == "Ravindra":

print("Ravindra is selected.") # Output: Ravindra is selected.

if word < "Ravindra":

print(f"Your name, {word}, comes before Ravindra.") # Output: Your name, Anil,
comes before Ravindra.

elif word > "Ravindra":

print(f"Your name, {word}, comes after Ravindra.")


else:

print("All right, Ravindra.")

• How It Works: Python compares the ASCII values of corresponding characters. For ,
Anil < Ravindra is True because the ASCII value of A (65) is less than that of R (82).

4. String Traversal

Traversal involves iterating through each character in a string to perform some action. This
can be done using a for loop or a while loop.

• Using a for Loop:

fruit = "grapes"

for char in fruit:

print(char, end="\t") # Output: g r a p e s

• Using a while Loop:

st = "Roopa"

index = 0

while index < len(st):

print(st[index], end="\t") # Output: R o o p a

index += 1

5. String Slicing

Explanation:

• Slicing extracts a portion (substring) from a string.

• Syntax: string[start:end:step] (end is exclusive).

• You can omit start, end, or step values.

• Negative steps allow reversing the string.

• Slicing always creates a new string, original remains unchanged.

s = "Python"

print(s[1:4]) # yth

print(s[::-1]) # nohtyP
6. String Repetition

Explanation:

• Use * operator to repeat a string multiple times.

• Helpful for creating repeated patterns quickly.

• Works only with integer multipliers.

• Useful in design layouts and text formatting.

• Creates a new string each time.

s = "Hi"

print(s * 3) # HiHiHi

7. Finding Substrings

Explanation:

• .find(substring) returns the first index where the substring appears.

• .rfind() returns the last occurrence from the right.

• .index() is similar to .find(), but throws an error if not found.

• Useful for checking or extracting parts of text.

• Returns -1 if the substring isn't found (in find).

s = "hello world"

print(s.find("world")) # 6

8. Replacing Substrings

Explanation:

• .replace(old, new) replaces all occurrences of old with new.

• Does not modify the original string (strings are immutable).

• Useful for cleaning data (e.g., removing unwanted words).

• You can chain multiple .replace() for complex changes.

• Can replace even if the substring appears multiple times.

s = "bad dog"
print(s.replace("bad", "good")) # good dog

Accessing Characters in Strings by Index Numbers in


Python
In Python, a string is a sequence of characters, and each character in the string can be
accessed individually using an index number.

Indexing allows programmers to retrieve specific characters from a string based on their
position.

Python supports both positive indexing (starting from the beginning) and negative
indexing (starting from the end), making it versatile for string manipulation.

This feature is fundamental for tasks such as parsing text, extracting substrings, or
processing individual characters.

Accessing Characters by Index Numbers

1. Concept of Indexing

• Each character in a string is assigned a unique index, which is an integer


representing its position in the sequence.

• Indexing in Python is zero-based, meaning the first character has an index of 0, the
second character has an index of 1, and so on.

• The index value must be an integer (or an expression that evaluates to an integer).

• Python also supports negative indexing, where the last character has an index of -1,
the second-to-last has an index of -2, and so forth.

2. Syntax

To access a character in a string, use square brackets ([]) with the index number:

string_name[index]

• string_name: The string from which to retrieve the character.

• index: An integer specifying the position of the character (positive or negative).

3. Positive Indexing
Positive indices are used to access characters from the start of the string. The index starts
at 0 for the first character and increments by 1 for each subsequent character.

• word = "Python"

print(word[0]) # Output: P (character at index 0)

print(word[1]) # Output: y (character at index 1)

print(word[5]) # Output: n (character at index 5)

• Illustration:

For the string "good morning":

s = "good morning"

print(s[0]) # Output: g

print(s[5]) # Output: m

print(s[11]) # Output: g

• Dynamic Indexing: The index can be an expression that evaluates to an integer.

i=2

print(s[i + 1]) # Output: d (accesses index 3)

4. Negative Indexing

Negative indices allow access to characters from the end of the string. The last character
has an index of -1, the second-to-last has an index of -2, and so on.

word = "Python"

print(word[-1]) # Output: n (last character)

print(word[-2]) # Output: o (second-last character)

print(word[-6]) # Output: P (first character)

• Illustration:

For the string "good morning":

s = "good morning"

print(s[-1]) # Output: g (last character)

print(s[-2]) # Output: n (second-last character)


print(s[-12]) # Output: g (first character)

• Use Case: Negative indexing is particularly useful when you need to access
characters relative to the end of a string without knowing its exact length.

5. Error Handling

Attempting to access an index that is out of range (i.e., greater than or equal to the string's
length or less than the negative length) results in an IndexError.

word = "Python"

print(word[6]) # IndexError: string index out of range

print(word[-7]) # IndexError: string index out of range

Prevention: Always ensure the index is within the valid range. You can use the len()
function to check the string's length:

word = "Python"

if 0 <= 5 < len(word):

print(word[5]) # Output: n

else:

print("Index out of range")

6. Applications of Indexing

• Extracting Specific Characters: Retrieve specific characters, such as the first letter
of a name or the last digit of a code.

• Parsing Strings: Process strings character by character, e.g., checking for vowels or
digits.

• Validation: Verify if a character at a specific position meets certain criteria (e.g.,


checking if a string starts with a letter).

• String Manipulation: Combine indexing with other operations like slicing or


concatenation for advanced text processing.

String Slicing and Joining in Python


In Python, strings are sequences of characters that support powerful operations for
manipulation. Two essential operations are string slicing and string joining.

String slicing allows you to extract a portion (or substring) of a string, while string joining
combines multiple strings into a single string using a separator.

These operations are fundamental for text processing, data parsing, and string formatting
in Python, leveraging the language's flexibility and simplicity.

String Slicing

1. Concept of String Slicing

• String slicing refers to extracting a segment (or slice) of a string by specifying a


range of indices.

• Slicing creates a new string containing the selected characters without modifying
the original string (since strings are immutable).

• Slicing is performed using the colon (:) operator within square brackets, allowing you
to specify the start, end, and step (stride) of the slice.

2. Syntax

The syntax for string slicing is:

string_name[start:end:step]

• start: The index where the slice begins (inclusive). If omitted, defaults to 0 (start of
the string).

• end: The index where the slice ends (exclusive). If omitted, defaults to the length of
the string.

• step: The increment between indices (also called stride). If omitted, defaults to 1. A
negative step reverses the direction of the slice.

3. How Slicing Works

• The slice includes characters from the start index up to, but not including, the end
index.

• The step determines how indices are incremented (e.g., every character, every
second character, or in reverse).

• Slicing is versatile and can be used with positive or negative indices.


4. s of String Slicing

Consider the string s = "abcdefghij":

Index 0 1 2 3 4 5 6 7 8 9

Character a b c d e f g h i j

Negative Index -10 -9 -8 -7 -6 -5 -4 -3 -2 -1

Here are various slicing s:

• Basic Slicing:

print(s[2:5]) # Output: cde (characters at indices 2, 3, 4)

• Omitting Start (Defaults to 0):

print(s[:5]) # Output: abcde (first five characters)

• Omitting End (Defaults to Length):

print(s[5:]) # Output: fghij (from index 5 to the end)

• Using Negative Indices:

print(s[-2:]) # Output: ij (last two characters)

• Full String:

print(s[:]) # Output: abcdefghij (entire string)

• Using Step:

print(s[1:7:2]) # Output: bdf (characters from index 1 to 6, every second character)

• Reversing a String:

print(s[::-1]) # Output: jihgfedcba (negative step reverses the string)

5. Key Points about Slicing

• Out-of-Range Indices: Python handles out-of-range indices gracefully. If start is


less than 0, it is treated as 0. If end exceeds the string length, it is treated as the
string's length.

• print(s[-100:3]) # Output: abc (start -100 treated as 0)

print(s[4:100]) # Output: efghij (end 100 treated as len(s))


• Empty Slice: If the slice range is invalid (e.g., start >= end with a positive step), an
empty string is returned.

print(s[5:2]) # Output: '' (empty string, as start > end)

• Immutability: Slicing does not modify the original string; it returns a new string.

• Applications: Slicing is used for tasks like extracting substrings, reversing strings,
skipping characters, or parsing structured text (e.g., extracting a file extension from
a filename).

String Joining

1. Concept of String Joining

• String joining is the process of concatenating multiple strings into a single string,
typically with a specified separator (delimiter) between each string.

• The join() method is used to perform this operation, combining elements of an


iterable (e.g., a list or tuple of strings) into a single string.

• Joining is the inverse of splitting, where a string is broken into a list of substrings.

2. Syntax

The syntax for the join() method is:

separator.join(iterable)

• separator: The string used to separate the elements (e.g., ", ", "-", or an empty string

• iterable: An iterable (e.g., list, tuple, or string) containing the strings to be joined.

3. How Joining Works

• The join() method takes each element from the iterable, converts it to a string (if
necessary), and concatenates them, inserting the separator between each pair of
elements.

• The result is a single string containing all elements with the separator.

4. s of String Joining

• Joining a List of Strings:

words = ['this', 'is', 'python']

result = ' '.join(words)


print(result) # Output: this is python

• Using a Different Separator:

s1 = '-'

s2 = ['a', 'b', 'c']

print(s1.join(s2)) # Output: a-b-c

• Joining Characters of a String:

s1 = 'abc'

s2 = '123'

print(s1.join(s2)) # Output: 1abc2abc3

Explanation: The string s1 (abc) is inserted between each character of s2 (123), resulting in
1abc2abc3.

• Joining with an Empty Separator:

chars = ['p', 'y', 't', 'h', 'o', 'n']

result = ''.join(chars)

print(result) # Output: python

5. Key Points about Joining

• Iterable Requirement: The join() method requires an iterable where all elements
can be converted to strings. Non-string elements (e.g., integers) will raise a
TypeError unless converted first.

nums = [1, 2, 3]

# print(','.join(nums)) # TypeError: sequence item 0: expected str instance, int found

print(','.join(str(num) for num in nums)) # Output: 1,2,3

String Methods
In Python, strings are immutable sequences of characters that come with a rich set of built-
in methods for manipulation.
These string methods are functions attached to string objects, allowing programmers to
perform operations like modifying case, searching, replacing, splitting, joining, and
formatting strings.

Since strings are objects in Python, these methods are accessed using the dot operator
(e.g., string.method()). This comprehensive guide covers all string methods available in
Python, as listed by the dir(str) function, with detailed explanations and s.

Overview of String Methods

Python provides a wide range of string methods, each designed for specific text-processing
tasks. These methods do not modify the original string (due to immutability) but return a
new string or other data types (e.g., lists, integers, or booleans) based on the operation. The
methods can be explored using the dir() function:

stuff = 'Hello world'

print(dir(stuff))

The methods starting with double underscores (e.g., __add__) are special methods (dunder
methods) that define operator behavior or internal functionality. This guide focuses on the
public string methods (non-dunder methods) used for common string operations.

1. Case Conversion Methods

These methods modify the case of characters in a string.

a. capitalize()

o Description: Returns a copy of the string with the first character capitalized
and the rest in lowercase.

o Syntax: string.capitalize()

o msg = "bengaluru"

print(msg.capitalize()) # Output: Bengaluru

o Use Case: Formatting proper nouns or sentence beginnings.

b. casefold()

o Description: Returns a lowercase version of the string optimized for


caseless comparisons. More aggressive than lower(), handling special
characters (e.g., German ß).

o Syntax: string.casefold()
o first = "india"

o second = "INDIA"

print(first.casefold() == second.casefold()) # Output: True

o Use Case: Case-insensitive comparisons in internationalization.

c. lower()

o Description: Returns a copy of the string with all characters converted to


lowercase.

o Syntax: string.lower()

o text = "HeLLo"

print(text.lower()) # Output: hello

o Use Case: Standardizing text for consistent processing.

d. upper()

o Description: Returns a copy of the string with all characters converted to


uppercase.

o Syntax: string.upper()

o text = "HeLLo"

print(text.upper()) # Output: HELLO

o Use Case: Formatting text for display or emphasis.

e. swapcase()

o Description: Returns a copy of the string with uppercase characters


converted to lowercase and vice versa.

o Syntax: string.swapcase()

o text = "HeLLo"

print(text.swapcase()) # Output: hEllO

o Use Case: Creating visual effects or toggling case for specific formatting.

f. title()
o Description: Returns a copy of the string with the first character of each
word capitalized and the rest in lowercase.

o Syntax: string.title()

o text = "hello world"

print(text.title()) # Output: Hello World

o Note: May not handle apostrophes correctly (e.g., "it's" becomes "It'S").

o Use Case: Formatting titles or headings.

2. Search and Find Methods

These methods locate substrings or check for their presence.

a. find(sub[, start[, end]])

o Description: Returns the lowest index where the substring sub is found
within string[start:end]. Returns -1 if not found.

o Syntax: string.find(sub, start=None, end=None)

o st = "calender of Feb.cal2019"

o print(st.find('cal')) # Output: 0

o print(st.find('cal', 10, 20)) # Output: 16

print(st.find('x')) # Output: -1

o Use Case: Searching for substrings in text processing.

b. index(sub[, start[, end]])

o Description: Like find(), but raises a ValueError if the substring is not found.

o Syntax: string.index(sub, start=None, end=None)

o st = "hello"

o print(st.index('l')) # Output: 2

# print(st.index('x')) # Raises ValueError

o Use Case: When you expect the substring to exist and want to handle errors
explicitly.

c. startswith(prefix[, start[, end]])


o Description: Returns True if the string starts with prefix, False otherwise.
prefix can be a string or tuple of strings.

o Syntax: string.startswith(prefix, start=None, end=None)

o text = "logical"

o print(text.startswith("l")) # Output: True

o print(text.startswith("L")) # Output: False (case-sensitive)

print(text.startswith(("l", "p"))) # Output: True

o Use Case: Validating string prefixes (e.g., checking file extensions).

d. endswith(suffix[, start[, end]])

o Description: Returns True if the string ends with suffix, False otherwise.
suffix can be a string or tuple of strings.

o Syntax: string.endswith(suffix, start=None, end=None)

o text = "hello.txt"

print(text.endswith(".txt")) # Output: True

o Use Case: Checking file types or URL endings.

3. Stripping and Justifying Methods

These methods remove characters or align text.

• strip([chars])

o Description: Returns a copy of the string with leading and trailing


whitespace (or specified chars) removed.

o Syntax: string.strip(chars=None)

st = " hello world "

print(st.strip()) # Output: hello world

st = "###Hello###"

print(st.strip('#')) # Output: Hello

o Use Case: Cleaning user input or removing delimiters.

• lstrip([chars])
o Description: Removes leading whitespace (or specified chars) from the
string.

o Syntax: string.lstrip(chars=None)

o st = " hello"

o print(st.lstrip()) # Output: hello

o st = "###hello"

print(st.lstrip('#')) # Output: hello

o Use Case: Removing prefixes or leading spaces.

• rstrip([chars])

o Description: Removes trailing whitespace (or specified chars) from the


string.

o Syntax: string.rstrip(chars=None)

o st = "hello "

o print(st.rstrip()) # Output: hello

o st = "hello###"

print(st.rstrip('#')) # Output: hello

o Use Case: Cleaning trailing characters.

4. Splitting and Partitioning Methods

These methods split strings into lists or tuples.

a. split(sep=None, maxsplit=-1)

o Description: Splits the string into a list of substrings based on sep. If sep is
None, splits on whitespace. maxsplit limits the number of splits.

o Syntax: string.split(sep=None, maxsplit=-1)

o text = "this is python"

o print(text.split()) # Output: ['this', 'is', 'python']

o text = "abc, def, ghi"

print(text.split(", ")) # Output: ['abc', 'def', 'ghi']


o Use Case: Parsing delimited data (e.g., CSV).

5. Replacement and Translation Methods

These methods modify string content.

a. replace(old, new[, count])

o Description: Returns a copy of the string with all occurrences of old


replaced by new. count limits the number of replacements.

o Syntax: string.replace(old, new, count=-1)

text = "banana"

print(text.replace('a', 'o')) # Output: bonono

print(text.replace('a', 'o', 2)) # Output: bonona

o Use Case: Correcting text or reformatting strings.

7. Character Testing Methods

These methods test properties of the string and return booleans.

a. isalnum()

o Description: Returns True if all characters are alphanumeric (letters or


digits) and the string is non-empty.

o Syntax: string.isalnum()

print("abc123".isalnum()) # Output: True

print("abc 123".isalnum()) # Output: False

o Use Case: Validating usernames or codes.

b. isalpha()

o Description: Returns True if all characters are letters and the string is non-
empty.

o Syntax: string.isalpha()

print("hello".isalpha()) # Output: True

print("hello123".isalpha()) # Output: False

o Use Case: Checking if input contains only letters.


c. isascii()

o Description: Returns True if all characters are ASCII (code points 0–127).

o Syntax: string.isascii()

o print("hello".isascii()) # Output: True

print("héllo".isascii()) # Output: False

o Use Case: Ensuring compatibility with ASCII-only systems.

d. isdecimal()

o Description: Returns True if all characters are decimal digits (0–9) and the
string is non-empty.

o Syntax: string.isdecimal()

o print("123".isdecimal()) # Output: True

print("12.3".isdecimal()) # Output: False

o Use Case: Validating numeric input for integers.

e. isdigit()

o Description: Returns True if all characters are digits (including Unicode


digits) and the string is non-empty.

o Syntax: string.isdigit()

o print("123".isdigit()) # Output: True

print("²".isdigit()) # Output: True (Unicode superscript)

o Use Case: Broader digit validation.

f. isnumeric()

o Description: Returns True if all characters are numeric (digits, fractions,


Roman numerals, etc.) and the string is non-empty.

o Syntax: string.isnumeric()

o print("123".isnumeric()) # Output: True

print("½".isnumeric()) # Output: True

o Use Case: Handling diverse numeric characters.


g. islower()

o Description: Returns True if all cased characters are lowercase and there is
at least one cased character.

o Syntax: string.islower()

o print("hello".islower()) # Output: True

print("Hello".islower()) # Output: False

o Use Case: Checking case for formatting rules.

h. isupper()

o Description: Returns True if all cased characters are uppercase and there is
at least one cased character.

o Syntax: string.isupper()

o print("HELLO".isupper()) # Output: True

print("Hello".isupper()) # Output: False

o Use Case: Validating uppercase text.

i. istitle()

o Description: Returns True if the string is in title case (each word starts with
an uppercase letter, followed by lowercase).

o Syntax: string.istitle()

o print("Hello World".istitle()) # Output: True

print("Hello world".istitle()) # Output: False

o Use Case: Checking title case formatting.

j. isspace()

o Description: Returns True if all characters are whitespace (spaces, tabs,


newlines) and the string is non-empty.

o Syntax: string.isspace()

o print(" \t\n".isspace()) # Output: True

print(" a ".isspace()) # Output: False


o Use Case: Detecting empty or whitespace-only strings.

Exploring Methods with Python Tools

• Using dir(): Lists all methods available for a string object.

print(dir("hello"))

• Using help(): Provides documentation for a specific method.

help(str.capitalize)

String Formatting
String formatting in Python is the process of creating strings by embedding values or
variables into predefined templates.

It allows developers to produce dynamic, readable, and well-structured text output, such
as generating user messages, reports, or formatted data.

Python offers multiple approaches to string formatting, each with its own syntax and use
cases.

These methods are essential for tasks like creating user interfaces, logging, or generating
structured output (e.g., JSON, HTML).

This guide covers all major string formatting techniques in Python, including the %
operator, str.format(), f-strings, and template strings, with detailed explanations and s.

String Formatting Methods

Python provides four primary methods for string formatting, each introduced at different
stages of the language's evolution. These methods are designed to balance simplicity,
flexibility, and performance.

1. %-Formatting (Old-Style Formatting)

Description

• It is inspired by C's printf function and uses format specifiers (e.g., %s, %d) to define
the type and format of inserted values.
• While still supported, it is considered outdated and less readable compared to
newer methods.

Format Specifiers

• %s: String (or any object with a string representation)

• %d or %i: Integer

• %f: Floating-point number

• %x or %X: Hexadecimal

• %.nf: Floating-point with n decimal places (e.g., %.2f)

name = "Alice"

age = 25

print("My name is %s and I am %d years old." % (name, age))

score = 95.678

print("Score: %.2f" % score)

Limitations

• Less readable for complex templates.

• Error-prone with multiple arguments (requires correct order and type matching).

• Not as flexible as newer methods for advanced formatting.

2. str.format() Method

Description

• Introduced in Python 2.6, the str.format() method uses curly braces {} as


placeholders in the string template.

• It is more versatile than %-formatting, supporting named placeholders, positional


arguments, and formatting options.

• While powerful, it can be verbose compared to f-strings.

Features

• Positional Arguments: Placeholders {0}, {1}, etc., specify argument order.

• Named Arguments: Placeholders like {name} use keyword arguments.


• Format Specifiers: Inside {}, e.g., {:.2f} for two decimal places.

• Reusable Placeholders: Specify the same index or name multiple times.

# Positional arguments

print("My name is {} and I am {} years old.".format("Bob", 30))

# Output: My name is Bob and I am 30 years old.

# Named arguments

print("Name: {name}, Age: {age}".format(name="Charlie", age=35))

# Output: Name: Charlie, Age: 35

# Formatting numbers

print("Price: ${:.2f}".format(19.999))

# Output: Price: $20.00

# Reusing placeholders

print("{0}, {0}, {1}".format("hello", "world"))

# Output: hello, hello, world

Limitations

• Verbose syntax compared to f-strings.

• Requires careful management of indices or names for large templates.

3. f-Strings (Formatted String Literals)

Description

• They use the prefix f or F and embed expressions directly inside curly braces {}
within the string.

• f-strings are highly readable and performant, as they are evaluated at runtime.

Features

• Direct Expressions: Embed variables, calculations, or function calls inside {}.

• Format Specifiers: Support the same formatting options as str.format() (e.g.,


{value:.2f}).
• Multiline Support: Can span multiple lines using triple quotes.

• Debugging: Since Python 3.8, ={} displays both the expression and its value (e.g.,
f"{x=}").

name = "David"

age = 40

print(f"My name is {name} and I am {age} years old.")

# Output: My name is David and I am 40 years old.

# Expressions

x = 10

print(f"Double of {x} is {x * 2}.")

# Output: Double of 10 is 20.

# Formatting numbers

price = 29.999

print(f"Price: ${price:.2f}")

# Output: Price: $30.00

# Debugging (Python 3.8+)

y=5

print(f"{y=}")

# Output: y=5

Advantages

• Concise and intuitive syntax.

• High performance due to compile-time evaluation.

• Supports complex expressions directly within placeholders.

Limitations

• Requires Python 3.6 or later.

• Less suitable for templates defined separately from data (e.g., in configuration files).
Advanced Formatting Techniques

1. Nested Formatting

• f-strings and str.format() allow nested expressions or format specifications.

width = 10

text = "hello"

print(f"{text:>{width}}") # Output: hello

2. Multiline Formatting

• f-strings and Template strings support multiline strings using triple quotes.

name = "Grace"

print(f"""Dear {name},

Thank you for your order. Team""")

Lists
In Python, a list is a versatile, mutable, and ordered collection of elements that can store
items of different data types (e.g., integers, strings, or even other lists).

Lists are one of Python's most commonly used data structures due to their flexibility and
ease of manipulation.

They are defined using square brackets [] and support a variety of operations for adding,
removing, and modifying elements.

Lists in Python

Characteristics of Lists

• Ordered: Elements maintain their insertion order, accessible via indices starting
from 0.

• Mutable: Elements can be changed, added, or removed after creation.

• Heterogeneous: Can contain elements of different types (e.g., [1, "hello", 3.14]).

• Dynamic: Lists can grow or shrink as elements are added or removed.

• Iterable: Can be traversed using loops (e.g., for or while).


Creating Lists
Lists can be created in several ways, depending on the use case and requirements. Below
are the primary methods for creating lists in Python:

1. Using Square Brackets

The most common way to create a list is by enclosing elements in square brackets [],
separated by commas.

• Syntax: list_name = [element1, element2, ...]

• fruits = ["apple", "banana", "orange"]

• numbers = [1, 2, 3, 4, 5]

• mixed = [1, "hello", 3.14, True]

• empty = [] # Empty list

• Use Case: Direct initialization with known elements.

2. Using the list() Constructor

The list() function can create a list from an iterable (e.g., string, tuple, range) or an empty
list.

• Syntax: list_name = list(iterable)

• chars = list("hello") # Convert string to list of characters

• range_list = list(range(5)) # Convert range to list

• empty_list = list() # Empty list

• print(chars) # Output: ['h', 'e', 'l', 'l', 'o']

• Use Case: Converting iterables to lists or creating empty lists programmatically.

3. List Comprehension

List comprehension provides a concise way to create lists by applying an expression to


each item in an iterable, optionally with a condition.

• Syntax: list_name = [expression for item in iterable if condition]

4. Using Repetition Operator (*)


The repetition operator * can create a list by repeating a sequence a specified number of
times.

• Syntax: list_name = [element] * n

zeros = [0] * 5

repeated = ["hello"] * 3

print(zeros) # Output: [0, 0, 0, 0, 0]

• Use Case: Initializing lists with repeated values (e.g., for counters or placeholders).

Nested

Basic List Operations


Lists support a variety of operations for accessing, modifying, and manipulating elements.
Below are the fundamental operations:

1. Accessing Elements

Elements in a list are accessed using their index, with zero-based indexing. Negative
indices access elements from the end.

• Syntax: list_name[index]

• fruits = ["apple", "banana", "orange"]

• print(fruits[0]) # Output: apple (first element)

• print(fruits[2]) # Output: orange (third element)

• print(fruits[-1]) # Output: orange (last element)

print(fruits[-2]) # Output: banana (second-last element)

• Error Handling: Accessing an invalid index raises an IndexError.

# print(fruits[3]) # IndexError: list index out of range

• Use Case: Retrieving specific elements for processing or display.

2. Slicing

Slicing extracts a portion of the list using a range of indices, returning a new list.
• Syntax: list_name[start:end:step]

o start: Starting index (inclusive, default 0).

o end: Ending index (exclusive, default length of list).

o step: Increment (default 1, negative for reverse).

• numbers = [0, 1, 2, 3, 4, 5]

• print(numbers[1:4]) # Output: [1, 2, 3]

• print(numbers[:3]) # Output: [0, 1, 2]

• print(numbers[3:]) # Output: [3, 4, 5]

• print(numbers[::2]) # Output: [0, 2, 4] (every second element)

print(numbers[::-1]) # Output: [5, 4, 3, 2, 1, 0] (reverse)

• Use Case: Extracting sublists, reversing lists, or skipping elements.

3. Modifying Elements

Lists are mutable, so elements can be changed by assigning new values to specific indices.

• Syntax: list_name[index] = value

• fruits = ["apple", "banana", "orange"]

• fruits[1] = "mango"

print(fruits) # Output: ['apple', 'mango', 'orange']

• Use Case: Updating individual elements based on conditions or user input.

4. Concatenation

The + operator combines two or more lists into a new list.

• Syntax: new_list = list1 + list2

• list1 = [1, 2, 3]

• list2 = [4, 5, 6]

• combined = list1 + list2

print(combined) # Output: [1, 2, 3, 4, 5, 6]

• Use Case: Merging lists for data aggregation.


5. Repetition

The * operator repeats a list a specified number of times.

• Syntax: new_list = list * n

• list1 = [1, 2]

• repeated = list1 * 3

print(repeated) # Output: [1, 2, 1, 2, 1, 2]

• Use Case: Creating lists with repeated patterns.

6. Membership Testing

The in and not in operators check if an element exists in a list, returning a boolean.

• Syntax: element in list or element not in list

• fruits = ["apple", "banana", "orange"]

• print("banana" in fruits) # Output: True

• print("grape" in fruits) # Output: False

print("apple" not in fruits) # Output: False

• Use Case: Validating input or filtering elements.

7. Length

The len() function returns the number of elements in a list.

• Syntax: len(list_name)

• numbers = [1, 2, 3, 4]

• print(len(numbers)) # Output: 4

print(len([])) # Output: 0

• Use Case: Checking list size for loops or validation.

8. Traversal

Lists can be traversed using loops to process each element.

• Using a for Loop:

• fruits = ["apple", "banana", "orange"]


• for fruit in fruits:

print(fruit, end=" ") # Output: apple banana orange

Indexing and Slicing in Lists


In Python, lists are ordered, mutable collections of elements that support efficient access
and manipulation through indexing and slicing.

Indexing allows you to access individual elements in a list using their position, while
slicing enables you to extract a portion of the list as a new list.

These operations are fundamental for working with lists, enabling tasks such as data
extraction, modification, and transformation.

Indexing in Lists

1. Concept of Indexing

• Each element in a list is assigned a unique index, which is an integer representing its
position.

• Python uses zero-based indexing, meaning the first element is at index 0, the
second at index 1, and so on.

• Lists also support negative indexing, where the last element is at index -1, the
second-to-last at -2, and so forth.

• Indexing allows direct access to elements for reading or modification, as lists are
mutable.

2. Syntax

To access an element in a list, use square brackets [] with the index:

list_name[index]

• list_name: The list from which to retrieve or modify an element.

• index: An integer (positive or negative) specifying the position.

3. Positive Indexing

Positive indices are used to access elements from the start of the list, beginning at index 0.

• fruits = ["apple", "banana", "orange", "grape"]


• print(fruits[0]) # Output: apple (first element)

print(fruits[2]) # Output: orange (third element)

• Illustration:

For the list numbers = [10, 20, 30, 40, 50]:

Element 10 20 30 40 50

Index 0 1 2 3 4

numbers = [10, 20, 30, 40, 50]

print(numbers[1]) # Output: 20

print(numbers[4]) # Output: 50

4. Negative Indexing

Negative indices allow access to elements from the end of the list, with -1 referring to the
last element.

• fruits = ["apple", "banana", "orange", "grape"]

• print(fruits[-1]) # Output: grape (last element)

print(fruits[-2]) # Output: orange (second-last element)

• Illustration:

For the list numbers = [10, 20, 30, 40, 50]:

Element 10 20 30 40 50

Negative Index -5 -4 -3 -2 -1

numbers = [10, 20, 30, 40, 50]

print(numbers[-1]) # Output: 50

print(numbers[-3]) # Output: 30

• Use Case: Negative indexing is useful for accessing elements relative to the end
without knowing the list's length.

5. Modifying Elements Using Indexing


Since lists are mutable, you can modify an element by assigning a new value to a specific
index.

• fruits = ["apple", "banana", "orange"]

• fruits[1] = "mango"

print(fruits) # Output: ['apple', 'mango', 'orange']

• Use Case: Updating specific elements based on conditions or user input.

7. Applications of Indexing

• Data Retrieval: Access specific elements (e.g., first item in a shopping list).

• Data Modification: Update elements (e.g., changing a score in a list).

• Validation: Check elements at specific positions (e.g., verifying a header in a data


list).

• Iteration: Use indices in loops for controlled traversal.

Slicing in Lists

1. Concept of Slicing

• Slicing extracts a portion of a list, returning a new list containing the selected
elements.

• Slicing is performed using a range of indices, specified with colons (:) in the format
start:end:step.

• Slicing is non-destructive, preserving the original list while creating a new one.

2. Syntax

The syntax for slicing a list is:

list_name[start:end:step]

• start: The index where the slice begins (inclusive). Defaults to 0 if omitted.

• end: The index where the slice ends (exclusive). Defaults to the list's length if
omitted.

• step: The increment between indices. Defaults to 1. A negative step reverses the
direction.

3. How Slicing Works


• The slice includes elements from the start index up to, but not including, the end
index.

• The step determines which elements are included (e.g., every element, every
second element, or in reverse).

• Slicing supports both positive and negative indices, making it highly flexible.

4. s of Slicing

Consider the list numbers = [0, 1, 2, 3, 4, 5, 6, 7]:

Index 0 1 2 3 4 5 6 7

Element 0 1 2 3 4 5 6 7

Negative Index -8 -7 -6 -5 -4 -3 -2 -1

• Basic Slicing:

print(numbers[2:5]) # Output: [2, 3, 4] (elements at indices 2, 3, 4)

• Omitting Start (Defaults to 0):

print(numbers[:4]) # Output: [0, 1, 2, 3] (first four elements)

• Omitting End (Defaults to Length):

print(numbers[4:]) # Output: [4, 5, 6, 7] (from index 4 to end)

• Using Negative Indices:

• print(numbers[-3:]) # Output: [5, 6, 7] (last three elements)

print(numbers[-5:-2]) # Output: [3, 4, 5]

• Full List:

print(numbers[:]) # Output: [0, 1, 2, 3, 4, 5, 6, 7] (copy of the list)

• Using Step:

print(numbers[1:6:2]) # Output: [1, 3, 5] (every second element from index 1 to 5)

• Reversing a List:

• print(numbers[::-1]) # Output: [7, 6, 5, 4, 3, 2, 1, 0] (reverse)

print(numbers[6:2:-1]) # Output: [6, 5, 4, 3] (reverse from index 6 to 3)


5. Modifying Lists Using Slicing

Slicing can be used to modify multiple elements at once by assigning a new list to a slice.
The assigned list does not need to have the same length as the slice.

numbers = [0, 1, 2, 3, 4, 5]

numbers[1:4] = [10, 20, 30] # Replace elements at indices 1, 2, 3

print(numbers) # Output: [0, 10, 20, 30, 4, 5]

numbers[2:3] = [100, 200] # Replace one element with two

• Use Case: Bulk updates or inserting elements into a list.

Built-in Functions Used with Lists


These built-in functions are general-purpose tools provided by Python to perform common
operations on lists, such as determining their length, finding maximum or minimum values,
sorting, summing elements, and more.

These functions are not specific to lists but are frequently used with them due to lists'
iterable and sequence-based nature.

Built-in Functions for Lists

Python's built-in functions that are commonly used with lists operate on iterables or
sequences, making them highly effective for list manipulation. Below is a comprehensive
list of these functions, focusing on their application to lists, with detailed explanations.

1. len()

• Description: Returns the number of elements in a list.

• Syntax: len(list)

• Return Type: Integer

• fruits = ["apple", "banana", "orange"]

• print(len(fruits)) # Output: 3

• empty = []

print(len(empty)) # Output: 0
2. max()

• Description: Returns the largest element in a list based on comparison. For lists
with mixed types, elements must be comparable.

• Syntax: max(list[, key][, default])

o key: Optional function to customize comparison (e.g., key=len for strings).

o default: Value to return if the list is empty (Python 3.4+).

• Return Type: Element from the list

numbers = [5, 2, 8, 1, 9]

print(max(numbers)) # Output: 9

words = ["apple", "banana", "cherry"]

print(max(words)) # Output: cherry (lexicographical order)

print(max(words, key=len)) # Output: banana (longest string)

• Notes:

o Raises ValueError if the list is empty and no default is provided.

o Raises TypeError if elements are not comparable (e.g., max([1, "two"])).

3. min()

• Description: Returns the smallest element in a list based on comparison. Similar to


max() in functionality.

• Syntax: min(list[, key][, default])

• Return Type: Element from the list

numbers = [5, 2, 8, 1, 9]

print(min(numbers)) # Output: 1

words = ["apple", "banana", "cherry"]

print(min(words)) # Output: apple

print(min(words, key=len)) # Output: apple (shortest string)

4. sum()
• Description: Returns the sum of all elements in a list. Elements must be numeric
(integers, floats, etc.).

• Syntax: sum(list[, start])

o start: Optional value to add to the sum (defaults to 0).

numbers = [1, 2, 3, 4]

print(sum(numbers)) # Output: 10

print(sum(numbers, 5)) # Output: 15 (10 + 5)

5. sorted()

• Description: Returns a new sorted list from the elements of the input list. Does not
modify the original list.

• Syntax: sorted(list[, key][, reverse])

o key: Optional function to customize sorting (e.g., key=len).

o reverse: Boolean to sort in descending order (default False).

• Return Type: New list

numbers = [5, 2, 8, 1, 9]

print(sorted(numbers)) # Output: [1, 2, 5, 8, 9]

print(sorted(numbers, reverse=True)) # Output: [9, 8, 5, 2, 1]

words = ["banana", "apple", "cherry"]

print(sorted(words, key=len)) # Output: ['apple', 'banana', 'cherry']

6. all()

• Description: Returns True if all elements in the list are truthy or if the list is empty.

• Syntax: all(list)

• Return Type: Boolean

numbers = [1, 2, 3, 4]

print(all(numbers)) # Output: True (all non-zero)

• empty = []

print(all(empty)) # Output: True (empty list)


7. any()

• Description: Returns True if at least one element in the list is truthy. Returns False
for an empty list.

• Syntax: any(list)

• Return Type: Boolean

numbers = [0, 0, 1, 0]

print(any(numbers)) # Output: True (1 is truthy)

9. zip()

• Description: Combines multiple lists (or iterables) into an iterator of tuples, where
each tuple contains the corresponding elements from each list.

• Syntax: zip(*lists)

• Return Type: Iterator of tuples

names = ["Alice", "Bob", "Charlie"]

scores = [85, 90, 88]

for name, score in zip(names, scores):

print(f"{name}: {score}")

List Methods
These methods are specific to lists and are distinct from built-in functions (e.g., len(),
sorted()) that work with multiple types. The methods can be explored using the dir()
function:

my_list = [1, 2, 3]

print(dir(my_list))

Output (list of list methods, excluding dunder methods):

['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
The dunder methods (e.g., __add__, __len__) handle internal operations like operators and
are not covered here, as they are not typically called directly. This guide focuses on the 11
public list methods, organized by functionality.

1. Appending and Extending Methods

These methods add elements to a list.

a. append(object)

o Description: Adds a single element (any Python object) to the end of the list.
Modifies the list in place.

o Syntax: list.append(object)

fruits = ["apple", "banana"]

fruits.append("orange")

print(fruits) # Output: ['apple', 'banana', 'orange']

b. extend(iterable)

o Description: Adds each element from an iterable (e.g., list, tuple, string) to
the end of the list. Modifies the list in place.

o Syntax: list.extend(iterable)

numbers = [1, 2, 3]

numbers.extend([4, 5])

o print(numbers) # Output: [1, 2, 3, 4, 5]

c. insert(index, object)

o Description: Inserts an element at the specified index, shifting subsequent


elements to the right. Modifies the list in place.

o Syntax: list.insert(index, object)

fruits = ["apple", "banana", "orange"]

fruits.insert(1, "mango")

print(fruits) # Output: ['apple', 'mango', 'banana', 'orange']

2. Removing Elements
These methods remove elements from a list.

a. pop([index])

o Description: Removes and returns the element at the specified index. If no


index is provided, removes and returns the last element. Modifies the list in
place.

o Syntax: list.pop(index=-1)

numbers = [1, 2, 3, 4]

o last = numbers.pop()

o print(last) # Output: 4

b. remove(value)

o Description: Removes the first occurrence of the specified value from the
list. Modifies the list in place.

o Syntax: list.remove(value)

fruits = ["apple", "banana", "apple", "orange"]

fruits.remove("apple")

print(fruits) # Output: ['banana', 'apple', 'orange']

c. clear()

o Description: Removes all elements from the list, leaving it empty. Modifies
the list in place.

o Syntax: list.clear()

numbers = [1, 2, 3]

numbers.clear()

print(numbers) # Output: []

3. Searching and Counting Methods

These methods locate or count elements in a list.

a. index(value[, start[, end]])


o Description: Returns the index of the first occurrence of value in the list
within the range start to end. Raises ValueError if not found.

o Syntax: list.index(value, start=0, end=len(list))

o fruits = ["apple", "banana", "orange", "banana"]

o print(fruits.index("banana")) # Output: 1

b. count(value)

o Description: Returns the number of occurrences of value in the list.

o Syntax: list.count(value)

o numbers = [1, 2, 2, 3, 2]

o print(numbers.count(2)) # Output: 3

4. Sorting and Reversing Methods

a. sort(key=None, reverse=False)

o Description: Sorts the list in place, using the Timsort algorithm. The key
function customizes the sort order, and reverse=True sorts in descending
order.

o Syntax: list.sort(key=None, reverse=False)

numbers = [5, 2, 8, 1, 9]

numbers.sort()

print(numbers) # Output: [1, 2, 5, 8, 9]

numbers.sort(reverse=True)

print(numbers) # Output: [9, 8, 5, 2, 1]

words = ["banana", "apple", "cherry"]

words.sort(key=len)

b. reverse()

o Description: Reverses the order of elements in the list in place.

o Syntax: list.reverse()

numbers = [1, 2, 3, 4]
o numbers.reverse()

print(numbers) # Output: [4, 3, 2, 1]

5. Copying Method

This method creates a copy of the list.

a. copy()

o Description: Returns a shallow copy of the list, creating a new list with the
same elements.

o Syntax: list.copy()

o original = [1, 2, 3]

o duplicate = original.copy()

o duplicate.append(4)

o print(original) # Output: [1, 2, 3]

o print(duplicate) # Output: [1, 2, 3, 4]

Sets in Python
In Python, a set is a built-in data structure that represents an unordered collection of
unique elements.

Sets are highly efficient for operations like membership testing, eliminating duplicates, and
performing mathematical set operations (e.g., union, intersection).

They are mutable (can be modified) but can only contain immutable (hashable) elements,
such as numbers, strings, or tuples.

Sets are particularly useful in scenarios requiring uniqueness and fast lookups.

Characteristics of Sets

• Unordered: Elements in a set have no defined order, and indexing is not supported.

• Unique Elements: Duplicate elements are automatically removed.

• Mutable: Sets can be modified by adding or removing elements (though frozenset is


immutable).
• Hashable Elements: Only immutable types (e.g., integers, strings, tuples) can be
elements, as sets rely on hashing.

• Iterable: Sets can be looped over, but the order of elements is not guaranteed.

Creating Sets
Sets can be created in several ways, depending on the use case. Below are the primary
methods for creating sets in Python:

1. Using Curly Braces {}

A set is created by enclosing elements in curly braces {}, separated by commas. Note that
an empty {} creates a dictionary, not a set.

• Syntax: set_name = {element1, element2, ...}

fruits = {"apple", "banana", "orange"}

print(fruits) # Output: {'apple', 'banana', 'orange'} (order may vary)

• numbers = {1, 2, 2, 3} # Duplicates are removed

print(numbers) # Output: {1, 2, 3}

2. Using the set() Constructor

The set() function creates a set from an iterable (e.g., list, tuple, string) or an empty set.

• Syntax: set_name = set(iterable)

chars = set("hello") # Convert string to set of characters

print(chars) # Output: {'h', 'e', 'l', 'o'}

3. Creating a Frozenset

A frozenset is an immutable version of a set, created using the frozenset() constructor.

• Syntax: frozenset_name = frozenset(iterable)

• frozen = frozenset([1, 2, 3])

• print(frozen) # Output: frozenset({1, 2, 3})

# frozen.add(4) # AttributeError: 'frozenset' has no attribute 'add'


Basic Set Operations
Sets support operations for membership testing, iteration, and mathematical set
operations. Below are the fundamental operations:

1. Membership Testing

The in and not in operators check if an element exists in a set, leveraging sets' efficient
hash-based lookup.

• Syntax: element in set or element not in set

• fruits = {"apple", "banana", "orange"}

• print("banana" in fruits) # Output: True

• print("grape" in fruits) # Output: False

print("apple" not in fruits) # Output: False

2. Iteration

Sets are iterable, allowing traversal using loops, though the order is not guaranteed.

• numbers = {1, 2, 3}

• for num in numbers:

print(num, end=" ") # Output: 1 2 3 (order may vary)

• Use Case: Processing all elements (e.g., printing or summing).

3. Length

The len() function returns the number of elements in a set.

• Syntax: len(set)

• fruits = {"apple", "banana", "orange"}

• print(len(fruits)) # Output: 3

print(len(set())) # Output: 0

4. Mathematical Set Operations


Sets support mathematical operations like union, intersection, difference, and symmetric
difference, either via operators or methods (covered later).

• Operators:

o Union (|): Combines elements from both sets.

o Intersection (&): Returns elements common to both sets.

o Difference (-): Returns elements in one set but not the other.

o Symmetric Difference (^): Returns elements in either set but not both.

a = {1, 2, 3}

b = {2, 3, 4}

print(a | b) # Union: {1, 2, 3, 4}

print(a & b) # Intersection: {2, 3}

print(a - b) # Difference: {1}

print(a ^ b) # Symmetric Difference: {1, 4}

Set Methods
Sets provide a rich set of methods for manipulation, many corresponding to mathematical
operations. Below are the key methods, grouped by functionality:

1. Adding Elements

a. add(elem)

o Description: Adds a single element to the set if it’s not already present.
Modifies the set in place.

fruits = {"apple", "banana"}

fruits.add("orange")

o print(fruits) # Output: {'apple', 'banana', 'orange'}

b. update(*others)

o Description: Adds elements from one or more iterables (e.g., lists, sets) to
the set. Modifies the set in place.

numbers = {1, 2}
numbers.update([2, 3, 4])

print(numbers) # Output: {1, 2, 3, 4}

2. Removing Elements

a. remove(elem)

o Description: Removes the specified element from the set. Raises KeyError if
the element is not found.

fruits = {"apple", "banana", "orange"}

fruits.remove("banana")

print(fruits) # Output: {'apple', 'orange'}

b. discard(elem)

o Description: Removes the specified element from the set if present. Does
not raise an error if the element is not found.

fruits = {"apple", "banana"}

fruits.discard("banana")

c. pop()

o Description: Removes and returns an arbitrary element from the set. Raises
KeyError if the set is empty.

numbers = {1, 2, 3}

elem = numbers.pop()

print(elem) # Output: 1 (arbitrary)

d. clear()

o Description: Removes all elements from the set, leaving it empty.

fruits = {"apple", "banana"}

fruits.clear()

3. Mathematical Set Operations

These methods perform set operations, similar to operators, and can modify the set in
place or return a new set.
a. union(*others) / |

o Description: Returns a new set containing all elements from the set and the
specified iterables.

a = {1, 2}

b = {2, 3}

print(a.union(b)) # Output: {1, 2, 3}

print(a | b) # Output: {1, 2, 3}

b. intersection(*others) / &

o Description: Returns a new set with elements common to the set and all
specified iterables.

o print(a.intersection(b)) # Output: {2, 3}

print(a & b) # Output: {2, 3}

c. difference(*others) / -

o Description: Returns a new set with elements in the set but not in the
specified iterables.

o print(a.difference(b)) # Output: {1}

print(a - b) # Output: {1}

d. symmetric_difference(other) / ^

o Description: Returns a new set with elements in either the set or the
specified iterable, but not both.

o print(a.symmetric_difference(b)) # Output: {1, 4}

print(a ^ b) # Output: {1, 4}

4. Testing Methods

a. issubset(other) / <= / <

o Description: Returns True if the set is a subset of other (all elements in the
set are in other). < checks for proper subset.

o print(a.issubset(b)) # Output: True


o print(a <= b) # Output: True

print(a < b) # Output: True

b. issuperset(other) / >= / >

o Description: Returns True if the set is a superset of other (all elements in


other are in the set). > checks for proper superset.

o print(a.issuperset(b)) # Output: True

print(a >= b) # Output: True

c. isdisjoint(other)

o Description: Returns True if the set has no elements in common with other.

print(a.isdisjoint(b)) # Output: True

Tuples in Python
In Python, a tuple is a built-in data structure that represents an ordered, immutable
collection of elements.

Tuples are similar to lists but cannot be modified after creation, making them suitable for
storing fixed data.

They can contain elements of any data type, including mixed types, and are highly efficient
for memory usage and performance.

Tuples are widely used for tasks requiring data integrity, such as returning multiple values
from functions or representing fixed collections.

Characteristics of Tuples

• Ordered: Elements maintain their insertion order, accessible via indices starting
from 0.

• Immutable: Once created, a tuple’s elements cannot be changed, added, or


removed.

• Heterogeneous: Can contain elements of different types (e.g., [1, "hello", 3.14]).

• Iterable: Tuples can be looped over using for or while loops.


• Hashable: Tuples are hashable if all their elements are hashable, allowing use as
dictionary keys or set elements.

• Lightweight: Tuples use less memory than lists due to immutability.

Creating Tuples
Tuples can be created in several ways, offering flexibility for different use cases. Below are
the primary methods for creating tuples in Python:

1. Using Parentheses

The most common way to create a tuple is by enclosing elements in parentheses (),
separated by commas. Parentheses are optional for non-empty tuples.

• Syntax: tuple_name = (element1, element2, ...)

• fruits = ("apple", "banana", "orange")

• numbers = (1, 2, 3)

• mixed = (1, "hello", 3.14)

• single = (42,) # Single-element tuple requires a trailing comma

• empty = () # Empty tuple

2. Without Parentheses (Comma-Separated Values)

Tuples can be created by listing elements separated by commas, without parentheses,


often used in tuple unpacking or function returns.

• Syntax: tuple_name = element1, element2, ...

• coords = 10, 20

• print(coords) # Output: (10, 20)

3. Using the tuple() Constructor

The tuple() function creates a tuple from an iterable (e.g., list, string, range) or an empty
tuple.

• Syntax: tuple_name = tuple(iterable)

• chars = tuple("hello") # Convert string to tuple

• print(chars) # Output: ('h', 'e', 'l', 'l', 'o')


Basic Tuple Operations
Tuples support operations for accessing, combining, and testing elements, though their
immutability limits modification. Below are the fundamental operations:

1. Accessing Elements (Indexing)

Elements are accessed using zero-based indices, with negative indices for accessing from
the end.

• Syntax: tuple_name[index]

• fruits = ("apple", "banana", "orange")

• print(fruits[0]) # Output: apple

• print(fruits[2]) # Output: orange

• print(fruits[-1]) # Output: orange (last element)

2. Slicing

Slicing extracts a portion of the tuple, returning a new tuple.

• Syntax: tuple_name[start:end:step]

• numbers = (0, 1, 2, 3, 4, 5)

• print(numbers[1:4]) # Output: (1, 2, 3)

• print(numbers[:3]) # Output: (0, 1, 2)

• print(numbers[3:]) # Output: (3, 4, 5)

• print(numbers[::2]) # Output: (0, 2, 4) (every second element)

3. Concatenation

The + operator combines two or more tuples into a new tuple.

• Syntax: new_tuple = tuple1 + tuple2

• tuple1 = (1, 2)

• tuple2 = (3, 4)

• combined = tuple1 + tuple2


print(combined) # Output: (1, 2, 3, 4)

4. Repetition

The * operator repeats a tuple a specified number of times, creating a new tuple.

• Syntax: new_tuple = tuple * n

• tuple1 = (1, 2)

• repeated = tuple1 * 3

print(repeated) # Output: (1, 2, 1, 2, 1, 2)

5. Membership Testing

The in and not in operators check if an element exists in a tuple.

• Syntax: element in tuple or element not in tuple

• fruits = ("apple", "banana", "orange")

• print("banana" in fruits) # Output: True

• print("grape" in fruits) # Output: False

print("apple" not in fruits) # Output: False

6. Length

The len() function returns the number of elements in a tuple.

• Syntax: len(tuple)

• numbers = (1, 2, 3)

• print(len(numbers)) # Output: 3

print(len(())) # Output: 0

Tuple Methods
Tuples have only two built-in methods due to their immutability, focusing on searching and
counting elements.

1. count(value)

• Description: Returns the number of occurrences of value in the tuple.


• Syntax: tuple.count(value)

• numbers = (1, 2, 2, 3, 2)

• print(numbers.count(2)) # Output: 3

print(numbers.count(4)) # Output: 0

2. index(value[, start[, end]])

• Description: Returns the index of the first occurrence of value in the tuple within
the range start to end. Raises ValueError if not found.

• Syntax: tuple.index(value, start=0, end=len(tuple))

• fruits = ("apple", "banana", "orange", "banana")

• print(fruits.index("banana")) # Output: 1

• print(fruits.index("banana", 2)) # Output: 3

# print(fruits.index("grape")) # ValueError

Built-in functions of tuple


Even though not technically "methods", you can apply these built-in functions on tuples:

Since tuples are immutable, there are very few methods directly available for them.
However, many built-in functions can operate on tuples.

Function Explanation

len(tuple) Returns the number of items in the tuple.

Returns the maximum value in the tuple (works if elements are comparable,
max(tuple)
like numbers or strings).

min(tuple) Returns the minimum value in the tuple.

Adds up all the numbers in the tuple (only works if the elements are
sum(tuple)
numbers).

Returns a sorted list of the tuple's elements (original tuple remains


sorted(tuple)
unchanged).
Function Explanation

all(tuple) Returns True if all elements of the tuple are True.

count(x) Tuple method: Returns how many times x appears in the tuple.

index(x) Tuple method: Returns the index of the first occurrence of x in the tuple.

Dictionaries
In Python, a dictionary is a built-in data structure that stores data in key-value pairs,
providing an efficient way to map unique keys to values.

Dictionaries are unordered , mutable, and highly versatile, making them ideal for tasks like
data lookup, configuration storage, and data organization.

Keys must be immutable and hashable (e.g., strings, numbers, tuples), while values can be
of any type.

Characteristics of Dictionaries

• Key-Value Pairs: Each key is associated with a value, forming a mapping (e.g.,
{"name": "Alice", "age": 25}).

• Unordered (Pre-3.7): No guaranteed order of keys before Python 3.7; ordered by


insertion in Python 3.7+.

• Mutable: Dictionaries can be modified by adding, updating, or removing key-value


pairs.

• Unique Keys: Keys must be unique; duplicate keys overwrite existing values.

• Hashable Keys: Keys must be immutable (e.g., strings, numbers, tuples with
immutable elements).

• Iterable: Dictionaries can be looped over to access keys, values, or key-value pairs.

• Dynamic: Dictionaries can grow or shrink as needed.

Creating Dictionaries
Dictionaries can be created in several ways, offering flexibility for different use cases.
Below are the primary methods for creating dictionaries in Python:

1. Using Curly Braces

A dictionary is created by enclosing key-value pairs in curly braces {}, with keys and values
separated by colons : and pairs separated by commas.

• Syntax: dict_name = {key1: value1, key2: value2, ...}

• person = {"name": "Alice", "age": 25, "city": "New York"}

• print(person) # Output: {'name': 'Alice', 'age': 25, 'city': 'New York'}

• empty_dict = {}

print(empty_dict) # Output: {}

2. Using the dict() Constructor

The dict() function creates a dictionary from an iterable of key-value pairs, keyword
arguments, or an empty dictionary.

• Syntax: dict_name = dict(iterable) or dict_name = dict(key1=value1, key2=value2)

• # From iterable (list of tuples)

• pairs = [("name", "Bob"), ("age", 30)]

• person = dict(pairs)

• print(person) # Output: {'name': 'Bob', 'age': 30}

• # From keyword arguments

• student = dict(name="Charlie", grade=85)

• print(student) # Output: {'name': 'Charlie', 'grade': 85}

• empty_dict = dict()

print(empty_dict) # Output: {}

3. Using Dictionary Comprehension

Dictionary comprehension creates a dictionary by applying an expression to each item in


an iterable, optionally with a condition.

• Syntax: dict_name = {key_expr: value_expr for item in iterable if condition}


4. From zip() or Other Iterables

The zip() function can pair two iterables (e.g., lists) to create a dictionary.

• keys = ["name", "age"]

• values = ["David", 40]

• person = dict(zip(keys, values))

print(person) # Output: {'name': 'David', 'age': 40}

Basic Dictionary Operations


Dictionaries support operations for accessing, modifying, and iterating over key-value
pairs. Below are the fundamental operations:

1. Accessing Values

Values are accessed using keys in square brackets [] or the get() method.

• Using Square Brackets:

o Syntax: dict_name[key]

o person = {"name": "Alice", "age": 25}

o print(person["name"]) # Output: Alice

# print(person["city"]) # KeyError: 'city'

• Using get():

o Syntax: dict_name.get(key[, default])

o print(person.get("age")) # Output: 25

print(person.get("city", "Unknown")) # Output: Unknown (default value)

2. Modifying Values

Dictionaries are mutable, so values can be updated or new key-value pairs added using
assignment.

• Syntax: dict_name[key] = value

• person = {"name": "Alice", "age": 25}


• person["age"] = 26 # Update existing key

• person["city"] = "Boston" # Add new key-value pair

print(person) # Output: {'name': 'Alice', 'age': 26, 'city': 'Boston'}

3. Removing Key-Value Pairs

Key-value pairs can be removed using del, pop(), or popitem().

• Using del:

o Syntax: del dict_name[key]

o person = {"name": "Alice", "age": 25}

o del person["age"]

print(person) # Output: {'name': 'Alice'}

• Using pop():

o Syntax: dict_name.pop(key[, default])

o person = {"name": "Alice", "age": 25}

o age = person.pop("age")

o print(age) # Output: 25

o print(person) # Output: {'name': 'Alice'}

print(person.pop("city", "Not found")) # Output: Not found

4. Membership Testing

The in and not in operators check if a key exists in the dictionary.

• Syntax: key in dict or key not in dict

• person = {"name": "Alice", "age": 25}

• print("name" in person) # Output: True

• print("city" in person) # Output: False

print("age" not in person) # Output: False

5. Length

The len() function returns the number of key-value pairs in the dictionary.
• Syntax: len(dict)

• person = {"name": "Alice", "age": 25}

• print(len(person)) # Output: 2

print(len({})) # Output: 0

6. Iteration

Dictionaries can be iterated over to access keys, values, or key-value pairs.

• Iterating Over Keys (default):

• person = {"name": "Alice", "age": 25}

• for key in person:

print(key, person[key]) # Output: name Alice, age 25

• Using keys():

• for key in person.keys():

print(key) # Output: name, age

• Using values():

• for value in person.values():

print(value) # Output: Alice, 25

• Using items():

• for key, value in person.items():

print(f"{key}: {value}") # Output: name: Alice, age: 25

• Use Case: Processing dictionary data (e.g., generating reports or summing values).

Dictionary Methods
Dictionaries provide a variety of built-in methods for manipulation. Below are the key
methods, organized by functionality:

1. Accessing Methods

a. get(key[, default])
o Description: Returns the value for key if it exists; otherwise, returns default
(or None if not specified).

o person = {"name": "Alice"}

o print(person.get("name")) # Output: Alice

print(person.get("age", 0)) # Output: 0

b. keys()

o Description: Returns a view object of all keys in the dictionary.

o person = {"name": "Alice", "age": 25}

print(person.keys()) # Output: dict_keys(['name', 'age'])

c. values()

o Description: Returns a view object of all values in the dictionary.

print(person.values()) # Output: dict_values(['Alice', 25])

d. items()

o Description: Returns a view object of key-value pairs as tuples.

print(person.items()) # Output: dict_items([('name', 'Alice'), ('age', 25)])

o Use Case: Iterating over key-value pairs.

2. Modifying Methods

• update([other])

o Description: Updates the dictionary with key-value pairs from another


dictionary or iterable, overwriting existing keys.

o person = {"name": "Alice"}

o person.update({"age": 25, "city": "Boston"})

print(person) # Output: {'name': 'Bob', 'age': 25, 'city': 'Boston', 'grade': 85}

• setdefault(key[, default])

o Description: Returns the value for key if it exists; otherwise, inserts key with
default value and returns default.

o person = {"name": "Alice"}


o print(person.setdefault("age", 25)) # Output: 25

o print(person) # Output: {'name': 'Alice', 'age': 25}

print(person.setdefault("name", "Bob")) # Output: Alice (key exists)

3. Removing Methods

• pop(key[, default])

o Description: Removes and returns the value for key. Returns default if key is
not found, or raises KeyError if no default.

o person = {"name": "Alice", "age": 25}

o print(person.pop("age")) # Output: 25

print(person) # Output: {'name': 'Alice'}

• popitem()

o Description: Removes and returns the last inserted key-value pair as a tuple
(Python 3.7+).

o person = {"name": "Alice", "age": 25}

o print(person.popitem()) # Output: ('age', 25)

print(person) # Output: {'name': 'Alice'}

• clear()

o Description: Removes all key-value pairs, leaving an empty dictionary.

o person = {"name": "Alice"}

o person.clear()

print(person) # Output: {}

4. Copying Method

a. copy()

o Description: Returns a shallow copy of the dictionary.

o person = {"name": "Alice", "scores": [90, 95]}

o duplicate = person.copy()

o duplicate["scores"][0] = 99 # Modifies nested list in both


print(person) # Output: {'name': 'Alice', 'scores': [99, 95]}

5. sorts

Purpose Syntax

Sort dictionary by keys dict(sorted(d.items()))

Sort dictionary by values dict(sorted(d.items(), key=lambda item: item[1]))

Descending by keys dict(sorted(d.items(), reverse=True))

Descending by values dict(sorted(d.items(), key=lambda item: item[1], reverse=True))

Built-in Functions for Dictionaries


These built-in functions can be applied to dictionaries:

Function Purpose

len(dictionary) Returns the number of key-value pairs.

sorted(dictionary) Returns a sorted list of keys.

type(dictionary) Returns the type (dict).

dict() Creates a new dictionary.

all(dictionary) Returns True if all keys are True.

max(dictionary) Returns the maximum key (based on Unicode or numerical value).

min(dictionary) Returns the minimum key.

Files, Reading Files, and Writing Files in Python


In Python, file handling is a fundamental feature that allows programs to interact with files
on the filesystem, enabling data persistence and processing.

Files can be read to retrieve data or written to store data, supporting various formats like
text, CSV, JSON, or binary. Python provides built-in functions and methods to perform
reading and writing operations efficiently, with robust mechanisms for managing file
access and ensuring data integrity.

Understanding Files in Python

What is a File?

A file is a named location on a storage device used to store data permanently. Files can
contain text, binary data, or structured formats (e.g., CSV, JSON). Python interacts with files
through file objects, which provide methods for reading, writing, and managing file
operations.

Types of Files

• Text Files: Store human-readable data as strings (e.g., .txt, .csv, .json). Encoded in
formats like UTF-8.

• Binary Files: Store non-text data (e.g., images, audio, executables) in bytes (e.g.,
.jpg, .mp3, .bin).

File Operations

Python supports the following core file operations:

• Opening: Accessing a file for reading, writing, or both.

• Reading: Retrieving data from a file.

• Writing: Storing data in a file.

• Closing: Releasing system resources associated with the file.

File Handling Basics


Opening a File

Python uses the built-in open() function to create a file object, which serves as an interface
to the file.

• Syntax: file_object = open(file_name, mode, encoding=None)

o file_name: Path to the file (relative or absolute, e.g., "data.txt" or


"C:/files/data.txt").
o mode: Specifies the operation and file type (e.g., read, write, text, binary).

o encoding: Specifies the character encoding for text files (e.g., "utf-8").
Ignored for binary modes.

• Common File Modes:

Mode Description Notes

"r" Read (text, default) File must exist; raises FileNotFoundError if not.

"w" Write (text) Creates file if it doesn’t exist; overwrites if it does.

"a" Append (text) Appends to file; creates if it doesn’t exist.

"rb" Read (binary) For binary files (e.g., images).

"wb" Write (binary) For binary files; overwrites existing.

"ab" Append (binary) Appends to binary files.

"r+" Read and write (text) File must exist; allows both operations.

"w+" Write and read (text) Creates/overwrites file; allows both operations.

• file = open(".txt", "r", encoding="utf-8")

file.close()

• Note: Always close files after use to free resources, typically using close() or a with
statement.

The with Statement

The with statement is the preferred way to handle files, as it automatically closes the file,
even if an error occurs.

• Syntax:

• with open(file_name, mode, encoding=None) as file_object:

# File operations

• with open(".txt", "r", encoding="utf-8") as file:

• content = file.read()

# File is automatically closed after the block


• Use Case: Ensures proper resource management and simplifies error handling.

Reading Files

Reading a file involves retrieving its contents into memory for processing. Python provides
several methods to read text and binary files, with options to read all content, specific
lines, or chunks.

Methods for Reading Text Files

a. read(size=-1)

o Description: Reads up to size characters from the file as a single string. If


size is omitted or negative, reads the entire file.

o with open(".txt", "r", encoding="utf-8") as file:

o content = file.read()

print(content) # Outputs entire file content

o Use Case: Reading small files or when the entire content is needed.

o Note: For large files, reading the entire content may consume significant
memory.

b. readline(size=-1)

o Description: Reads a single line up to size characters or until a newline (\n).


Returns an empty string at the end of the file.

with open(".txt", "r", encoding="utf-8") as file:

o line1 = file.readline()

o line2 = file.readline()

print(line1, line2) # Outputs first two lines

o Use Case: Processing files line by line (e.g., parsing logs).

c. readlines()

o Description: Reads all lines into a list, with each line as a string

o with open(".txt", "r", encoding="utf-8") as file:


o lines = file.readlines()

print(lines) # Output: ['line1\n', 'line2\n', ...]

o Use Case: Loading all lines for batch processing.

d. Iterating Over Lines:

o File objects are iterable, allowing direct looping over lines.

o with open(".txt", "r", encoding="utf-8") as file:

o for line in file:

print(line.strip()) # Outputs each line, stripped of \n

o Use Case: Memory-efficient processing of large files line by line.

Reading Binary Files

Binary files are read in bytes using binary modes ("rb", "r+b"). The methods are similar but
return bytes objects.

• with open("image.jpg", "rb") as file:

• data = file.read() # Reads entire file as bytes

print(data[:10]) # Outputs first 10 bytes

• Use Case: Reading non-text files like images, audio, or serialized data.

Error Handling

• FileNotFoundError: Raised if the file does not exist in read mode.

• try:

• with open("nonexistent.txt", "r") as file:

• content = file.read()

• except FileNotFoundError:

print("File not found")

Writing Files

Writing a file involves storing data into a file, either creating a new file or modifying an
existing one. Python supports writing text and binary data with various methods.
Methods for Writing Text Files

a. write(string)

o Description: Writes the string to the file and returns the number of
characters written. Does not add newlines automatically.

o with open("output.txt", "w", encoding="utf-8") as file:

o file.write("Hello, World!")

o file.write("Second line.") # Appends immediately

o Use Case: Writing continuous text or data.

b. writelines(lines)

o Description: Writes a list of strings to the file without adding newlines.

o lines = ["Line 1\n", "Line 2\n", "Line 3\n"]

o with open("output.txt", "w", encoding="utf-8") as file:

o file.writelines(lines)

o Use Case: Writing multiple lines efficiently.

Writing Binary Files

Binary files are written in bytes using binary modes ("wb", "ab", "w+b").

• with open("output.bin", "wb") as file:

file.write(b"Binary data")

• Use Case: Writing non-text data like images or serialized objects.

Append Mode

In append mode ("a"), data is added to the end of the file without overwriting existing:

• with open("log.txt", "a", encoding="utf-8") as file:

• file.write("New log entry\n")

• Use Case: Logging or incrementally adding data.

Error Handling

• PermissionError: Raised if the program lacks write permissions.


• try:

• with open("/protected/output.txt", "w") as file:

• file.write("Data")

• except PermissionError:

print("Permission denied")

Practical Applications

• Reading Files:

o Configuration Files: Read settings from a .txt or .json file.

o with open("config.txt", "r") as file:

settings = file.readlines()

o Data Processing: Parse CSV files line by line.

o with open("data.csv", "r") as file:

o for line in file:

print(line.split(","))

• Writing Files:

o Logging: Append log messages to a file.

o with open("log.txt", "a") as file:

file.write("Error occurred\n")

o Data Export: Write processed data to a file.

o data = ["Item 1", "Item 2"]

o with open("output.txt", "w") as file:

file.writelines([f"{item}\n" for item in data])

Object oriented programming


Class
Class Definition

A class in Python is a user-defined blueprint or prototype for creating objects. It


encapsulates data (attributes) and functions (methods) into a single entity, facilitating
object-oriented programming (OOP).

Classes are defined using the class keyword, followed by the class name and a colon. The
class body contains attributes and methods that define the behavior and properties of
objects created from the class.

• Classes help organize code and model real-world entities like Car, Student,
Employee, etc.

• In Python, a class is created using the class keyword.

• The class itself does not occupy memory until an object is created from it.

class Car:

pass

2. Defining a Class with Attributes and Methods


• Attributes are variables inside a class that hold data.

• Methods are functions inside a class that perform actions.

• The __init__() method is a constructor that initializes object attributes when an


object is created.

class Car:

def __init__(self, brand, model):

self.brand = brand

self.model = model

def show_details(self):

print(f"Brand: {self.brand}, Model: {self.model}")

• self represents the instance (object) itself.

3. What is an Object?

• An Object is an instance of a class.

• When a class is defined, no memory is allocated. Memory is allocated when an


object is created.

• Objects can have their own data and can call methods defined in the class.

car1 = Car("Toyota", "Camry")

car2 = Car("Honda", "Accord")

car1.show_details() # Brand: Toyota, Model: Camry

car2.show_details() # Brand: Honda, Model: Accord

• Here, car1 and car2 are two different objects with their own attributes.

4. Attributes in Classes

(a) Instance Attributes

• Defined inside the __init__() method.

• Unique to each object.


• Created using self.attribute_name.

class Student:

def __init__(self, name, age):

self.name = name

self.age = age

Here, name and age are instance attributes.

(b) Class Attributes

• Shared by all instances of the class.

• Defined directly inside the class, outside any methods.

class Student:

school_name = "ABC High School" # class attribute

def __init__(self, name):

self.name = name

• Every student will belong to "ABC High School" by default.

5. Accessing and Modifying Attributes

• Access attributes using object.attribute.

• Modify attributes by simple assignment.

student1 = Student("Alice")

print(student1.name) # Alice

print(student1.school_name) # ABC High School

student1.name = "Bob" # Modifying instance attribute

Student.school_name = "XYZ Academy" # Modifying class attribute

print(student1.school_name) # XYZ Academy


7. Deleting Attributes and Objects

• Use the del keyword to delete attributes or objects.

del car1.model # deletes the 'model' attribute

del car1

Constructor Method (__init__) in Python


1. What is a Constructor?

• A constructor is a special method that is automatically called when a new object


of a class is created.

• In Python, the constructor method is named __init__().

• It is mainly used to initialize attributes (i.e., assign initial values) to the newly
created object.

• You don't call the constructor manually; Python calls it when you create an object.

• Every class has a constructor, either defined by the user or provided by Python by
default.

2. Syntax of Constructor

class ClassName:

def __init__(self, parameters):

• self refers to the current instance of the class.

• Additional parameters can be passed to initialize data.

3. Purpose of Constructor

• To set default or initial values to object attributes.

• To perform any startup activities needed when the object is created.

• Helps in automatic and clean object setup.


• Reduces chances of uninitialized object attributes.

4. Simple Example of Constructor

class Student:

def __init__(self, name, age):

self.name = name

self.age = age

# Creating an object

s1 = Student("Alice", 20)

print(s1.name) # Output: Alice

print(s1.age) # Output: 20

5. Types of Constructors

(a) Default Constructor

• Constructor without any parameters (other than self).

• Useful when no input from user is required.

class Example:

def __init__(self):

self.msg = "Hello World"

obj = Example()

print(obj.msg) # Output: Hello World

(b) Parameterized Constructor

• Constructor that accepts parameters to initialize object attributes.

• Gives flexibility to initialize different values for different objects.

class Employee:
def __init__(self, name, salary):

self.name = name

self.salary = salary

emp1 = Employee("John", 50000)

emp2 = Employee("Jane", 60000)

print(emp1.name, emp1.salary) # John 50000

print(emp2.name, emp2.salary) # Jane 60000

6. Constructor Overriding

• Python does not support multiple constructors (like C++ or Java).

• If you define multiple __init__() methods, only the last one is considered.

• You can simulate multiple constructors using default arguments.

class Demo:

def __init__(self, name="Guest"):

self.name = name

d1 = Demo()

d2 = Demo("Alex")

Inheritance in Python
1. What is Inheritance?

• Inheritance is a fundamental concept of Object-Oriented Programming (OOP).

• It allows a new class (child class) to reuse or inherit attributes and methods from
an existing class (parent class).

• Inheritance promotes code reusability and method overriding.

• The child class can extend or modify the behavior of the parent class.

• It models real-world relationships like “A dog is a type of animal.”


2. Syntax of Inheritance

class ParentClass:

# parent attributes and methods

class ChildClass(ParentClass):

# child attributes and methods

• The parent class name is placed inside parentheses in the child class definition.

• The child class automatically gets all public attributes and methods of the parent
class.

3. Simple Example of Inheritance

class Animal:

def speak(self):

print("Animal speaks")

class Dog(Animal):

pass

d = Dog()

d.speak() # Output: Animal speaks

4. Types of Inheritance in Python

Type Description Example

Single Inheritance One child inherits from one parent Dog → Animal

Multiple Inheritance One child inherits from multiple parents Child → Father, Mother

Multilevel Child inherits from parent, which inherits Grandchild → Child →


Inheritance from grandparent Parent
Type Description Example

Hierarchical
Multiple children inherit from one parent Dog, Cat → Animal
Inheritance

Hybrid Inheritance Combination of multiple types Mixed scenarios

5. Single Inheritance

class Parent:

def function1(self):

print("This is Parent class")

class Child(Parent):

def function2(self):

print("This is Child class")

c = Child()

c.function1() # Inherited from Parent

c.function2() # Own method

6. Multiple Inheritance

• A child class can inherit from more than one parent class.

class Father:

def skills(self):

print("Gardening")

class Mother:

def skills(self):

print("Cooking")

class Child(Father, Mother):

pass
c = Child()

c.skills() # Gardening (because Father is listed first)

7. Method Overriding

• A child class can redefine a method of the parent class to modify its behavior.

• This is called method overriding.

class Animal:

def speak(self):

print("Animal speaks")

class Dog(Animal):

def speak(self):

print("Dog barks")

d = Dog()

d.speak() # Output: Dog barks

8. The super() Function

• super() is used to call methods from the parent class inside the child class.

• Helpful especially when overriding constructors or methods.

class Person:

def __init__(self, name):

self.name = name

class Student(Person):

def __init__(self, name, course):

super().__init__(name)

self.course = course

s = Student("Alice", "Maths")

print(s.name) # Alice
print(s.course) # Maths

9. Advantages of Inheritance

• Code Reusability: Methods and attributes of the parent class can be reused.

• Less Redundancy: No need to duplicate common functionality.

• Extensibility: Easy to extend or modify behaviors of existing classes.

• Organization: Clean and modular program structure.

Overloading and Operator Overloading in Python


1. What is Overloading?

• Overloading in programming means giving multiple meanings to the same name


(function or operator).

• The behavior depends on the number or type of arguments or context.

• Python does not support traditional function overloading like C++ or Java.

• Instead, Python uses:

o Default arguments or

o Variable-length arguments (*args, **kwargs)


to simulate overloading.

2. Function Overloading in Python

• Python does not allow defining two methods with the same name but different
parameters.

• Last defined method overwrites the previous one.

Wrong Overloading (Not possible in Python):

# Only the second greet() survives

def greet(name):
print("Hello", name)

def greet(name, message):

print(message, name)
Use default arguments to simulate overloading.

class Greet:

def greet(self, name=None):

if name:

print("Hello", name)

else:

print("Hello there!")

g = Greet()

g.greet() # Hello there!

g.greet("Alice") # Hello Alice

3. Operator Overloading

• Operator Overloading allows custom behavior when standard operators (+, -, *,


etc.) are used with user-defined objects.

• Python lets you define special methods (also called magic methods) like __add__,
__sub__, __mul__, etc.

• This helps make classes behave more like built-in types.

4. Special (Magic) Methods for Operator Overloading

Operator Magic Method Example

+ __add__(self, other) Addition

- __sub__(self, other) Subtraction

* __mul__(self, other) Multiplication

/ __truediv__(self, other) Division


Operator Magic Method Example

// __floordiv__(self, other) Floor Division

% __mod__(self, other) Modulus

** __pow__(self, other) Exponentiation

== __eq__(self, other) Equal to

5. Example of Operator Overloading

class Point:

def __init__(self, x, y):

self.x = x

self.y = y

def __add__(self, other):

return Point(self.x + other.x, self.y + other.y)

def __str__(self):

return f"({self.x}, {self.y})"

p1 = Point(1, 2)

p2 = Point(3, 4)

p3 = p1 + p2 # Calls __add__()

print(p3) # Output: (4, 6)

6. Important Points about Operator Overloading

• Operators behave differently based on types because of overloading.

• You must define magic methods carefully to avoid confusion.

• Always return a new object rather than modifying existing objects unless
necessary.
• Python already overloads operators for built-in types (like + for integers, strings,
lists).

Polymorphism in Python
1. What is Polymorphism?

• Polymorphism is a core concept in Object-Oriented Programming (OOP).

• The word Polymorphism comes from two Greek words:

o Poly = Many

o Morph = Forms

• It means the ability to take many forms.

• In Python, polymorphism allows different classes to have methods with the same
name, but potentially different behaviors.

• The exact method that is called is decided at runtime based on the object's class.

2. Importance of Polymorphism

• Promotes flexibility and code reusability.

• Allows writing general-purpose code that can work with objects of different types.

• Makes programs more modular, extensible, and easier to manage.

• Supports the "programming to interface" idea (use common method names


across different classes).

3. Types of Polymorphism

Type Description

Compile-time Polymorphism (not fully Traditional method overloading, not natively


supported in Python) available in Python
Type Description

Method overriding (decides at runtime which


Run-time Polymorphism
method to call)

Python supports mainly run-time polymorphism.

4. Polymorphism with Functions and Objects

Example 1: Polymorphism with Functions

def add(x, y, z=0):

return x + y + z

print(add(2, 3)) # Output: 5

print(add(2, 3, 4)) # Output: 9

PROGRAM
# -------------------- BASE CLASS WITH ENCAPSULATION --------------------
class Student:
def __init__(self, name, subject1, subject2, subject3):
self.name = name # Public attribute
self.__subject1 = subject1 # Private attributes (encapsulation)
self.__subject2 = subject2
self.__subject3 = subject3
def calculate_percentage(self):
total = self.__subject1 + self.__subject2 + self.__subject3
percentage = total / 3
return percentage

def get_subject_marks(self):
# Safely access private marks
return (self.__subject1, self.__subject2, self.__subject3)
# -------------------- INHERITANCE --------------------
class SchoolStudent(Student):
def __init__(self, name, subject1, subject2, subject3, school_name):
super().__init__(name, subject1, subject2, subject3) # Call base class constructor
self.school_name = school_name

def display_info(self):
print(f"Student Name: {self.name}")
print(f"School Name: {self.school_name}")
print(f"Marks: {self.get_subject_marks()}")
print(f"Percentage: {self.calculate_percentage():.2f}%")
# -------------------- FUNCTION OVERLOADING USING DEFAULT ARGUMENTS ------------------
class Calculator:
def add(self, a, b, c=0):
return a + b + c # Add two or three numbers depending on input
# -------------------- POLYMORPHISM --------------------
def show_student_details(student):
student.display_info()
# -------------------- MAIN PROGRAM --------------------
# Creating objects
print("\n--- Student Data Entry ---")
stu1 = SchoolStudent("Amit", 85, 90, 80, "Greenwood High")
stu2 = SchoolStudent("Riya", 78, 88, 92, "Sunrise Academy")
# Encapsulation Example
print("\n--- Encapsulation ---")
print(f"{stu1.name}'s marks are {stu1.get_subject_marks()}") # Using method to get private
data
# Inheritance and Polymorphism Example
print("\n--- Inheritance and Polymorphism ---")
show_student_details(stu1) # Student 1 details
show_student_details(stu2) # Student 2 details
# Function Overloading Example
print("\n--- Function Overloading ---")
calc = Calculator()
print(f"Sum of 10 and 20: {calc.add(10, 20)}")
print(f"Sum of 10, 20 and 30: {calc.add(10, 20, 30)}")

Difference Between Lists, Sets, Tuples, and Dictionaries


Feature List Set Tuple Dictionary

An unordered An ordered,
An ordered An unordered
collection of immutable
Definition collection of collection of
unique collection of
elements. key-value pairs.
elements. elements.

Does NOT Maintains Maintains


Maintains
Order maintain any insertion insertion order
insertion order.
order. order. (Python 3.7+).

Immutable
Mutable (can be Mutable (can be Mutable (can be
Mutability (cannot be
changed). changed). changed).
changed).

Keys must be
Not allowed (all
unique; values
Duplicates Allowed. elements must Allowed.
can be
be unique).
duplicate.

Keys are
Supports Does not Supports
accessed
Indexing indexing and support indexing and
directly (no
slicing. indexing. slicing.
indexing).
Feature List Set Tuple Dictionary

Access
Access Access
elements by Access values
Access elements by elements by
looping (no using keys.
index. index.
direct access).

{ key: value }
[ ] (square ()
Syntax { } (curly braces) (curly braces
brackets) (parentheses)
with colon)

Usage Example [1, 2, 3, 4] {1, 2, 3, 4} (1, 2, 3, 4) {'a': 1, 'b': 2}

add(), remove(),
append(),
discard(), pop(), Few keys(), values(),
extend(),
union(), methods: items(), get(),
Methods/Functions insert(), pop(),
intersection(), count(), update(), pop(),
remove(), sort(),
difference(), index() etc.
reverse(), etc.
etc.

More memory
Least
(due to Less memory More memory
memory
Memory Consumption mutability and (no duplicates, (stores mapping
(immutable
dynamic unordered). of key to value).
and simple).
features).

Storing an Fixed
Associating
ordered Storing a collection of
keys with values
Best For collection when collection of items that
(mapping
duplicates are unique items. should not
relationships).
allowed. change.

Set of unique Storing a


List of student Storing (x, y)
Example Use Case email student’s ID
names. coordinates.
addresses. and marks.

List Set Dictionary


Not
Comprehensions Comprehension Comprehension Comprehension
applicable.
possible. possible. possible.

List elements Set elements Tuple


Mutable/Immutable Keys must be
can be of any must be elements can
Elements immutable (str,
data type. hashable be any type
int, tuple),
(immutable (even
Feature List Set Tuple Dictionary

types like int, mutable values can be


str, tuple). types like list any type.
inside tuple).

No direct Yes (tuple Yes (dictionary


Allow Nested Yes (list inside
nesting inside tuple, inside
Structures list, etc.).
recommended. etc.). dictionary, etc.).

list() set() tuple() dict()


Creation Function
constructor constructor constructor constructor

Example Code l = [1,2,3] s = {1,2,3} t = (1,2,3) d = {'a':1, 'b':2}

You might also like