Introduction to Python
Python is a high-level, general-purpose, and very popular programming language. It is being used in web development, Machine Learning applications, etc.
- High-level programs are generally smaller than other programming languages.
- Programmers have to type relatively less and the administrative requirements of the language makes fewer modules all the time.
Why Python?
- Very simple syntax & easy to learn
- General purpose language (Simple yet very powerful language)
- Console Application & Scripts
- Desktop Application
- Web Application
- Game Development
- Machine Learning, Deep learning, AI, Big data etc
Your First Python Program
print("Hello, World!")
Multi-paradigm Support
- Procedural Style Programming (like C)
- Object-Oriented Programming (like Java)
- Functional Programming (like LISP)
Key Features
- Portable: Platform Independent
- Dynamically Typed: No need to specify variable types
- Automatic Garbage Collection: Memory management handled automatically
Popular Applications Built in Python
YouTube, Netflix, Quora, Instagram, Dropbox.
Variables in Python
A variable is a name that is used to refer to memory location. Python variable is also known as an identifier.
Key Points:
- In Python, we don't need to specify the type of variable because Python is smart enough to get variable type
- Python is dynamically typed
Basic Variable Example:
price = 100
tax = 18
total = price + tax
print(total)
Python is Dynamically Typed
x = 10
print(x)
x = "geeks"
print(x)
Variable Naming Rules
- Variable names must start with a letter or underscore
- Cannot start with a number
- Can contain letters, numbers, and underscores
- Case-sensitive (age and Age are different)
- Cannot use Python keywords
Data Types in Python
Built-in Data Types
Python has several built-in data types to store different kinds of data:
- int: Integer numbers (e.g., 5, -3, 100)
- float: Decimal numbers (e.g., 3.14, -2.5)
- str: Text data (e.g., "Hello", 'Python')
- bool: Boolean values (True or False)
- list: Ordered collection of items
- tuple: Immutable ordered collection
- dict: Key-value pairs
- set: Unordered collection of unique items
Type() Function
Type() is a built-in function that tells you data type of a variable or a value.
a = 10
b = 10.5
c = 2+3j
d = "Hello"
e = True
print(type(a)) # int
print(type(b)) # float
print(type(c)) # complex
print(type(d)) # str
print(type(e)) # bool
<class 'float'>,
<class 'complex'>
<class 'str'>
<class 'bool'>
Type Conversions in Python
Types of Type Conversion
1. Implicit Type Conversion
Python automatically converts one data type to another when needed.
Example:
num_int = 123
num_float = 1.23
num_new = num_int + num_float
print("datatype of num_int:", type(num_int))
print("datatype of num_float:", type(num_float))
print("Value of num_new:", num_new)
print("datatype of num_new:", type(num_new))
datatype of num_float: <class 'float'>
Value of num_new: 124.23
datatype of num_new: <class 'float'>
2. Explicit Type Conversion
User converts the data type of an object to required data type using predefined functions.
Common Type Conversion Functions:
# String to Integer
str_num = "123"
int_num = int(str_num)
print(int_num, type(int_num))
# Integer to Float
int_val = 10
float_val = float(int_val)
print(float_val, type(float_val))
# Number to String
num = 456
str_val = str(num)
print(str_val, type(str_val))
# String to List
text = "hello"
list_val = list(text)
print(list_val, type(list_val))
10.0 <class 'float'>
456 <class 'str'>
['h', 'e', 'l', 'l', 'o'] <class 'list'>
Input() Function in Python
This function is used to take input from the user.
Basic Input Example:
name = input("Enter the name: ")
print("Welcome " + name)
Enter the name: Surya
Welcome Surya
Python Program for Addition
x = input("Enter First Number: ")
y = input("Enter Second Number: ")
x = int(x)
y = int(y)
z = x + y
print("Sum is", z)
Enter first number: 10
Enter second number: 20
Sum is: 30
Conditional Statements
There come situations in real life when we need to make decisions based on certain conditions. Similarly, there comes a situation in programming where a specific task is to be performed if a specific condition is true.
Types of Conditional Statements:
- if
- if-else
- nested if
- if-elif statements
If Statement
The if statement is used to execute a block of code only if a specified condition is true.
Syntax:
if condition:
# Statements to execute if condition is true
Example:
if 10 > 5:
print("10 is greater than 5")
print("Program ended")
10 is greater than 5
Program ended
If-else Statement
The if-else statement provides an alternative block that runs when the condition is false.
Syntax:
if condition:
# Statements inside body of if
else:
# Statements inside body of else
Example:
num = int(input("Enter a number: "))
if num % 2 == 0:
print("The number is Even.")
else:
print("The number is Odd.")
The number is Odd.
Nested if Statement
A nested if is an if statement inside another if or else block. It’s used for checking multiple conditions in a structured way.
Syntax:
if condition1:
if condition2:
# runs if both condition1 and condition2 are True
Example:
x = 10
if x > 0:
if x % 2 == 0:
print("x is a positive even number")
if-elif-else statement
The if-elif (else if) statement is used to check multiple conditions, one after another.
Syntax:
if condition1:
# runs if condition1 is True
elif condition2:
# runs if condition2 is True
else:
# runs if none of the above conditions are True
Example:
letter = "A"
if letter == "B":
print("letter is B")
elif letter == "C":
print("letter is C")
elif letter == "A":
print("letter is A")
else:
print("letter isn't A, B or C")
Operators and Types in Python
Operators are used to perform operations on values and variables. Python supports various types of operators.
1. Arithmetic Operators
Addition (+)
Adds two operands
a = 5
b = 3
result = a + b
print(result) # Output: 8
Subtraction (-)
Subtracts right operand from left
a = 5
b = 3
result = a - b
print(result) # Output: 2
Multiplication (*)
Multiplies two operands
a = 5
b = 3
result = a * b
print(result) # Output: 15
Division (/)
Divides left operand by right
a = 6
b = 3
result = a / b
print(result) # Output: 2.0
Floor Division (//)
Returns floor of the division
a = 7
b = 3
result = a // b
print(result) # Output: 2
Modulus (%)
Returns remainder of division
a = 7
b = 3
result = a % b
print(result) # Output: 1
Exponentiation (**)
Raises left operand to power of right
a = 2
b = 3
result = a ** b
print(result) # Output: 8
2. Comparison Operators
a = 5
b = 3
print(a == b) # Equal to: False
print(a != b) # Not equal to: True
print(a > b) # Greater than: True
print(a < b) # Less than: False
print(a >= b) # Greater than or equal to: True
print(a <= b) # Less than or equal to: False
3. Logical Operators
a = True
b = False
print(a and b) # Logical AND: False
print(a or b) # Logical OR: True
print(not a) # Logical NOT: False
4. Assignment Operators
x = 5
print(x) # 5
x += 3 # Same as x = x + 3
print(x) # 8
x -= 2 # Same as x = x - 2
print(x) # 6
x *= 2 # Same as x = x * 2
print(x) # 12
x /= 3 # Same as x = x / 3
print(x) # 4.0
Loops in Python
1. While Loop
It is used to execute a block of statements repeatedly until a given condition is satisfied.
Syntax:
while condition:
# statements to be executed
Example:
count = 0
while count < 5:
print("Hello Geek")
count = count + 1
2. For Loop
It is used for sequential traversal i.e., it is used for iterating over an iterable like String, Tuple, List, Set or Dictionary.
Syntax:
for variable in iterable:
# statements to be executed
Example:
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
3. Range() Function
Python range() is a built-in function that returns a sequence of numbers.
Syntax:
range(start, stop, step)
Examples:
# range(stop)
for i in range(5):
print(i, end=" ")
print() # Output: 0 1 2 3 4
# range(start, stop)
for i in range(2, 6):
print(i, end=" ")
print() # Output: 2 3 4 5
# range(start, stop, step)
for i in range(0, 10, 2):
print(i, end=" ")
print() # Output: 0 2 4 6 8
Nested Loops
Nested loop means loops inside a loop. For example, while loop inside the for loop, for loop inside the for loop, etc.
Example - Multiplication Table:
# Running outer loop from 2 to 3
for i in range(2, 4):
print(f"Multiplication table for {i}:")
# Running inner loop from 1 to 10
for j in range(1, 11):
print(f"{i} x {j} = {i * j}")
print() # Add blank line
2 x 1 = 2
2 x 2 = 4
...
2 x 10 = 20
Multiplication table for 3:
3 x 1 = 3
3 x 2 = 6
...
3 x 10 = 30
Pattern Example:
# Print a triangle pattern
for i in range(1, 6):
for j in range(i):
print("*", end=" ")
print() # New line after each row
*
* *
* * *
* * * *
* * * * *
Finding Prime Numbers:
for num in range(2, 11):
is_prime = True
for i in range(2, int(num/2) + 1):
if num % i == 0:
is_prime = False
break
if is_prime:
print(f"{num} is prime")
else:
print(f"{num} is not prime")
Break and Continue Statements
1. Break Statement
It is used to bring the control out of the loop when some external condition is triggered. Break statement terminates the current loop and resumes execution at the next statement.
Example:
for i in range(10):
print(i)
if i == 2:
break
0
1
2
Example with String:
s = 'geeksforgeeks'
for letter in s:
print(letter)
if letter == 'e':
break
print("Out of for loop")
g
e
Out of for loop
2. Continue Statement
It is a loop control statement that forces to execute the next iteration of the loop. When the continue statement is encountered inside the loop, it skips the remaining statements in the current iteration.
Example:
for val in "GeeksforGeeks":
if val == "s":
continue
print(val)
G
e
e
k
f
o
r
G
e
e
k
Skip Even Numbers:
for i in range(1, 11):
if i % 2 == 0:
continue
print(i, end=" ")
print() # Output: 1 3 5 7 9
Range() Function in Python
The range() function returns a sequence of numbers, starting from 0 by default, and increments by 1 (by default), and stops before a specified number.
Syntax
range(start, stop, step)
Parameters
- start - (Optional) Starting number of the sequence. Default is 0
- stop - (Required) Generate numbers up to, but not including this number
- step - (Optional) Difference between each number in the sequence. Default is 1
Different Range Examples:
# Using range with only stop parameter
print("range(5):")
for i in range(5):
print(i, end=" ")
print() # Output: 0 1 2 3 4
# Using range with start and stop parameters
print("range(2, 8):")
for i in range(2, 8):
print(i, end=" ")
print() # Output: 2 3 4 5 6 7
# Using range with start, stop and step parameters
print("range(2, 20, 3):")
for i in range(2, 20, 3):
print(i, end=" ")
print() # Output: 2 5 8 11 14 17
# Reverse range
print("range(10, 0, -2):")
for i in range(10, 0, -2):
print(i, end=" ")
print() # Output: 10 8 6 4 2
Converting Range to List
numbers = list(range(1, 6))
print(numbers) # Output: [1, 2, 3, 4, 5]
even_numbers = list(range(0, 11, 2))
print(even_numbers) # Output: [0, 2, 4, 6, 8, 10]
Functions in Python
Python function is a block of statements that return the specific task. The idea is to put some commonly or repeatedly done task together and make a function so that instead of writing the same code again and again for different inputs, we can do the function calls to reuse code contained in it over and over again.
Function Syntax
def function_name(parameters):
"""docstring"""
# body of the function
return expression
Simple Function Example:
def greet():
print("Welcome to Python!")
greet() # Calling the function
Function with Parameters
Example:
def evenOdd(x):
if (x % 2 == 0):
print("even")
else:
print("odd")
evenOdd(2)
evenOdd(3)
even
odd
Function with Return Statement
Example:
def square_value(num):
"""This function returns the square value of the entered number"""
return num**2
result1 = square_value(2)
result2 = square_value(-4)
print(result1) # 4
print(result2) # 16
Function with Multiple Parameters
def add_numbers(a, b, c=0):
"""Add two or three numbers"""
return a + b + c
print(add_numbers(5, 3)) # 8
print(add_numbers(5, 3, 2)) # 10
Arguments of a Python Function
Arguments are the values passed inside the parenthesis of the function. A function can have any number of arguments separated by a comma.
Example - A simple Python function to check whether x is even or odd:
def evenOdd(x):
if (x % 2 == 0):
print("even")
else:
print("odd")
evenOdd(2)
evenOdd(3)
even
odd
Pass by Reference or pass by value
One important thing to note in Python, every variable name is a reference. When we pass a variable to a function, a new reference to the object is created.
def myFun(x):
x[0] = 20
# Driver Code (Note that lst is modified after function call)
lst = [10, 11, 12, 13, 14, 15]
myFun(lst)
print(lst)
Immutable Objects:
def modify_number(x):
x = 20
print("Inside function:", x)
num = 10
modify_number(num)
print("Outside function:", num)
Inside function: 20
Outside function: 10
Arguments Types in Python
Types of Arguments:
1. Default Arguments
It is a parameter that assumes a default value if no argument is provided in the function call for that argument.
def myFun(x, y=50):
print("x: ", x)
print("y: ", y)
myFun(10)
myFun(10, 20)
x: 10
y: 50
x: 10
y: 20
2. Keyword Arguments
The idea is to allow the caller to specify the argument name with values so that caller does not need to remember the order of parameters.
def student(firstname, lastname):
print(firstname, lastname)
student(firstname='Geeks', lastname='Practice')
student(lastname='for', firstname='Geeks')
Geeks for
3. Variable-length Arguments (*args)
We can have both normal and keyword arguments. There are two special symbols: *args (Non-keyword Arguments)
def myFun(*argv):
for arg in argv:
print(arg)
myFun('Hello', 'Welcome', 'to', 'GeeksforGeeks')
4. Keyword Variable-length Arguments (**kwargs)
**kwargs allows you to pass keyworded variable length of arguments to a function.
def myFun(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
myFun(first='Geeks', mid='for', last='Geeks')
first: Geeks
mid: for
last: Geeks
5. Positional-only Arguments
def greet(name, /, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
# greet(name="Charlie") # This would cause an error
6. Keyword-only Arguments
def create_profile(name, *, age, city):
return f"Name: {name}, Age: {age}, City: {city}"
print(create_profile("Alice", age=30, city="New York"))
# create_profile("Alice", 30, "New York") # This would cause an error
Return Statement in Python Function
The function return statement is used to exit from a function and go back to the function caller and return the specified value or data item to the caller.
Syntax:
return [expression_list]
Example:
def square_value(num):
"""This function returns the square value of the entered number"""
return num**2
print(square_value(2))
print(square_value(-4))
4
16
Multiple Return Values
def calculate(a, b):
sum_result = a + b
diff_result = a - b
product_result = a * b
return sum_result, diff_result, product_result
result = calculate(10, 5)
print(result) # (15, 5, 50)
# Unpacking the returned values
add, sub, mul = calculate(10, 5)
print(f"Addition: {add}, Subtraction: {sub}, Multiplication: {mul}")
(15, 5, 50)
Addition: 15, Subtraction: 5, Multiplication: 50
Return with Conditional Statements
def check_grade(marks):
if marks >= 90:
return "A"
elif marks >= 80:
return "B"
elif marks >= 70:
return "C"
elif marks >= 60:
return "D"
else:
return "F"
print(check_grade(85)) # B
print(check_grade(92)) # A
print(check_grade(55)) # F
Lists & List Methods
Lists are used to store multiple items in a single variable. Lists are one of 4 built-in data types in Python used to store collections of data, the other 3 are Tuple, Set, and Dictionary, all with different qualities and usage.
Creating a List
# Creating an empty list
my_list = []
print("Empty list:", my_list)
# Creating a list with elements
fruits = ["apple", "banana", "cherry"]
print("Fruits list:", fruits)
# Creating a list with mixed data types
mixed_list = [1, "hello", 3.14, True]
print("Mixed list:", mixed_list)
Empty list: []
Fruits list: ['apple', 'banana', 'cherry']
Mixed list: [1, 'hello', 3.14, True]
List Methods
1. append() - Add an element to the end
fruits = ["apple", "banana"]
fruits.append("orange")
print(fruits) # ['apple', 'banana', 'orange']
2. insert() - Insert element at specific position
fruits = ["apple", "banana"]
fruits.insert(1, "orange")
print(fruits) # ['apple', 'orange', 'banana']
3. remove() - Remove first occurrence of element
fruits = ["apple", "banana", "orange", "banana"]
fruits.remove("banana")
print(fruits) # ['apple', 'orange', 'banana']
4. pop() - Remove element at given position
fruits = ["apple", "banana", "orange"]
removed_fruit = fruits.pop(1)
print(fruits) # ['apple', 'orange']
print(removed_fruit) # banana
5. index() - Find index of element
fruits = ["apple", "banana", "orange"]
index = fruits.index("banana")
print(index) # 1
6. count() - Count occurrences of element
numbers = [1, 2, 3, 2, 2, 4]
count = numbers.count(2)
print(count) # 3
7. sort() - Sort the list
numbers = [3, 1, 4, 1, 5, 9, 2]
numbers.sort()
print(numbers) # [1, 1, 2, 3, 4, 5, 9]
# Sort in reverse order
numbers.sort(reverse=True)
print(numbers) # [9, 5, 4, 3, 2, 1, 1]
8. reverse() - Reverse the list
fruits = ["apple", "banana", "orange"]
fruits.reverse()
print(fruits) # ['orange', 'banana', 'apple']
List Slicing
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(numbers[2:5]) # [2, 3, 4]
print(numbers[:3]) # [0, 1, 2]
print(numbers[7:]) # [7, 8, 9]
print(numbers[::2]) # [0, 2, 4, 6, 8]
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Sets in Python
Set in Python is an unordered collection data type that is iterable, mutable and has no duplicate elements. Sets are represented by { }.
Creating Sets
# Creating a set
my_set = {"apple", "banana", "cherry"}
print(my_set)
print(type(my_set))
# Creating a set from a list (removes duplicates)
numbers = [1, 2, 3, 2, 1, 4]
unique_numbers = set(numbers)
print(unique_numbers) # {1, 2, 3, 4}
{'apple', 'banana', 'cherry'}
<class 'set'>
{1, 2, 3, 4}
Set Methods
1. add() - Add an element
fruits = {"apple", "banana"}
fruits.add("orange")
print(fruits) # {'apple', 'banana', 'orange'}
2. remove() and discard()
fruits = {"apple", "banana", "orange"}
# remove() - raises error if element not found
fruits.remove("banana")
print(fruits) # {'apple', 'orange'}
# discard() - does not raise error if element not found
fruits.discard("grape") # No error
print(fruits) # {'apple', 'orange'}
3. Set Operations
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
# Union
print(set1 | set2) # {1, 2, 3, 4, 5, 6}
print(set1.union(set2)) # {1, 2, 3, 4, 5, 6}
# Intersection
print(set1 & set2) # {3, 4}
print(set1.intersection(set2)) # {3, 4}
# Difference
print(set1 - set2) # {1, 2}
print(set1.difference(set2)) # {1, 2}
# Symmetric Difference
print(set1 ^ set2) # {1, 2, 5, 6}
print(set1.symmetric_difference(set2)) # {1, 2, 5, 6}
Frozen Set
# Frozen set - immutable set
numbers = [1, 2, 3, 2, 1, 4]
frozen_set = frozenset(numbers)
print(frozen_set) # frozenset({1, 2, 3, 4})
print(type(frozen_set)) # <class 'frozenset'>
Since sets are unordered, we can't access items using indexes like we do in lists.
Dictionaries & Methods
Dictionary is a collection of key-value pairs, used to store data values like a map, which, unlike other Data Types that hold only a single value as an element.
Creating Dictionaries
# Creating a dictionary
student = {"name": "John", "age": 21, "grade": "A"}
print(student)
# Creating dictionary using dict() constructor
person = dict(name="Alice", age=25, city="New York")
print(person)
{'name': 'John', 'age': 21, 'grade': 'A'}
{'name': 'Alice', 'age': 25, 'city': 'New York'}
Accessing Dictionary Elements
student = {"name": "John", "age": 21, "grade": "A"}
# Using square brackets
print(student["name"]) # John
# Using get() method (safer)
print(student.get("age")) # 21
print(student.get("city")) # None
print(student.get("city", "Unknown")) # Unknown
Dictionary Methods
1. Adding/Updating Elements
student = {"name": "John", "age": 21}
# Adding new key-value pair
student["grade"] = "A"
print(student) # {'name': 'John', 'age': 21, 'grade': 'A'}
# Updating existing value
student["age"] = 22
print(student) # {'name': 'John', 'age': 22, 'grade': 'A'}
# Using update() method
student.update({"city": "Boston", "major": "CS"})
print(student)
2. keys(), values(), items()
student = {"name": "John", "age": 21, "grade": "A"}
# Get all keys
print(student.keys()) # dict_keys(['name', 'age', 'grade'])
# Get all values
print(student.values()) # dict_values(['John', 21, 'A'])
# Get all key-value pairs
print(student.items()) # dict_items([('name', 'John'), ('age', 21), ('grade', 'A')])
3. pop() and popitem()
student = {"name": "John", "age": 21, "grade": "A"}
# Remove specific key and return its value
age = student.pop("age")
print(age) # 21
print(student) # {'name': 'John', 'grade': 'A'}
# Remove and return arbitrary key-value pair
item = student.popitem()
print(item) # ('grade', 'A')
print(student) # {'name': 'John'}
4. Dictionary Comprehension
# Creating dictionary using comprehension
squares = {x: x**2 for x in range(1, 6)}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Dictionary comprehension with condition
even_squares = {x: x**2 for x in range(1, 11) if x % 2 == 0}
print(even_squares) # {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
Iterating Through Dictionaries
student = {"name": "John", "age": 21, "grade": "A"}
# Iterate through keys
for key in student:
print(key, ":", student[key])
# Iterate through key-value pairs
for key, value in student.items():
print(f"{key}: {value}")
# Iterate through values only
for value in student.values():
print(value)
Tuples
Python Tuple is a collection of objects separated by commas. In some ways, a tuple is similar to a list in terms of indexing, nested objects, and repetition but a tuple is immutable, unlike lists which are mutable.
Creating Tuples
# Creating a tuple
coordinates = (10, 20)
print(coordinates)
print(type(coordinates))
# Creating tuple without parentheses
point = 5, 10, 15
print(point)
print(type(point))
# Creating tuple with one element (note the comma)
single_item = (5,)
print(single_item)
print(type(single_item))
<class 'tuple'>
(5, 10, 15)
<class 'tuple'>
(5,)
<class 'tuple'>
Accessing Tuple Elements
fruits = ("apple", "banana", "cherry", "date")
# Positive indexing
print(fruits[0]) # apple
print(fruits[2]) # cherry
# Negative indexing
print(fruits[-1]) # date
print(fruits[-2]) # cherry
# Slicing
print(fruits[1:3]) # ('banana', 'cherry')
print(fruits[:2]) # ('apple', 'banana')
print(fruits[2:]) # ('cherry', 'date')
Tuple Methods
numbers = (1, 2, 3, 2, 4, 2, 5)
# count() - Count occurrences of a value
count_2 = numbers.count(2)
print(count_2) # 3
# index() - Find index of first occurrence
index_3 = numbers.index(3)
print(index_3) # 2
# len() - Get length of tuple
length = len(numbers)
print(length) # 7
Tuple Unpacking
# Tuple unpacking
point = (10, 20, 30)
x, y, z = point
print(f"x: {x}, y: {y}, z: {z}")
# Swapping variables using tuples
a = 5
b = 10
a, b = b, a
print(f"a: {a}, b: {b}") # a: 10, b: 5
# Function returning multiple values
def get_name_age():
return "Alice", 25
name, age = get_name_age()
print(f"Name: {name}, Age: {age}")
Built-in Functions with Tuples
numbers = (4, 1, 7, 2, 9, 3)
print(max(numbers)) # 9
print(min(numbers)) # 1
print(sum(numbers)) # 26
print(sorted(numbers)) # [1, 2, 3, 4, 7, 9] (returns a list)
# Converting tuple to list and vice versa
tuple_to_list = list(numbers)
print(tuple_to_list) # [4, 1, 7, 2, 9, 3]
list_to_tuple = tuple(tuple_to_list)
print(list_to_tuple) # (4, 1, 7, 2, 9, 3)
String Operations
Creating Strings
Strings in Python can be created using single, double or even triple quotes.
# Different ways to create strings
single_quote = 'Hello World'
double_quote = "Hello World"
triple_quote = """Hello World"""
multiline = """This is a
multiline string"""
print(single_quote)
print(double_quote)
print(triple_quote)
print(multiline)
String Indexing and Slicing
text = "Python Programming"
# Indexing
print(text[0]) # P
print(text[7]) # P
print(text[-1]) # g
# Slicing
print(text[0:6]) # Python
print(text[7:]) # Programming
print(text[:6]) # Python
print(text[::2]) # Pto rgamn
print(text[::-1]) # gnimmargorP nohtyP
String Methods
1. Case Methods
text = "Hello World"
print(text.lower()) # hello world
print(text.upper()) # HELLO WORLD
print(text.title()) # Hello World
print(text.capitalize()) # Hello world
print(text.swapcase()) # hELLO wORLD
2. Search and Check Methods
text = "Python Programming"
print(text.find("Pro")) # 7
print(text.index("Pro")) # 7
print(text.count("o")) # 2
print(text.startswith("Py")) # True
print(text.endswith("ing")) # True
print("Prog" in text) # True
3. Modification Methods
text = " Hello World "
print(text.strip()) # "Hello World"
print(text.replace("World", "Python")) # " Hello Python "
# Split and Join
sentence = "apple,banana,cherry"
fruits = sentence.split(",")
print(fruits) # ['apple', 'banana', 'cherry']
joined = " - ".join(fruits)
print(joined) # "apple - banana - cherry"
4. String Formatting
name = "Alice"
age = 25
grade = 85.7
# Old style formatting
print("Name: %s, Age: %d" % (name, age))
# .format() method
print("Name: {}, Age: {}".format(name, age))
print("Name: {0}, Age: {1}, Grade: {2:.1f}".format(name, age, grade))
# f-strings (Python 3.6+)
print(f"Name: {name}, Age: {age}")
print(f"Name: {name}, Age: {age}, Grade: {grade:.1f}")
# Advanced f-string formatting
print(f"Grade: {grade:>10.2f}") # Right-aligned, 2 decimal places
Escape Sequences
# Common escape sequences
print("Hello\nWorld") # New line
print("Hello\tWorld") # Tab
print("He said \"Hello\"") # Double quote
print('It\'s a nice day') # Single quote
print("Path: C:\\Users") # Backslash
# Raw strings (ignore escape sequences)
print(r"C:\Users\name\Documents")
String Validation Methods
print("123".isdigit()) # True
print("abc".isalpha()) # True
print("abc123".isalnum()) # True
print(" ".isspace()) # True
print("Hello World".istitle()) # True
print("HELLO".isupper()) # True
print("hello".islower()) # True
List Comprehensions
List comprehension provides a concise way to create lists. It consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses.
Basic Syntax
# Syntax: [expression for item in iterable]
# Syntax with condition: [expression for item in iterable if condition]
Basic List Comprehension
Traditional approach vs List Comprehension:
# Traditional approach
squares = []
for x in range(10):
squares.append(x**2)
print(squares)
# Using list comprehension
squares = [x**2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
List Comprehension with Conditions
# Even numbers from 0 to 19
evens = [x for x in range(20) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Squares of even numbers
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # [0, 4, 16, 36, 64]
# Filter words with length > 3
words = ["cat", "dog", "elephant", "lion", "tiger"]
long_words = [word for word in words if len(word) > 3]
print(long_words) # ['elephant', 'lion', 'tiger']
Nested List Comprehensions
# Create a 3x3 matrix
matrix = [[i*j for j in range(3)] for i in range(3)]
print(matrix) # [[0, 0, 0], [0, 1, 2], [0, 2, 4]]
# Flatten a 2D list
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Dictionary and Set Comprehensions
# Dictionary comprehension
squares_dict = {x: x**2 for x in range(5)}
print(squares_dict) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Set comprehension
unique_lengths = {len(word) for word in ["hello", "world", "python", "code"]}
print(unique_lengths) # {4, 5, 6}
# Dictionary comprehension with condition
even_squares_dict = {x: x**2 for x in range(10) if x % 2 == 0}
print(even_squares_dict) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
Advanced Examples
# Multiple conditions
numbers = [x for x in range(100) if x % 2 == 0 if x % 5 == 0]
print(numbers[:5]) # [0, 10, 20, 30, 40]
# Using functions in list comprehension
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True
primes = [x for x in range(2, 20) if is_prime(x)]
print(primes) # [2, 3, 5, 7, 11, 13, 17, 19]
# Working with strings
sentence = "Hello World Python"
vowels = [char for char in sentence.lower() if char in 'aeiou']
print(vowels) # ['e', 'o', 'o', 'o']
Object-Oriented Programming
OOPs is a programming paradigm that uses objects and classes in programming. It aims to implement real-world entities like inheritance, polymorphisms, encapsulation, etc. in the programming. The main concept of OOPs is to bind the data and the functions that work on together as a single unit so that no other part of the code can access this data.
Main Concepts of OOPs:
- Class - Blueprint for creating objects
- Objects - Instances of a class
- Inheritance - Acquiring properties from parent class
- Polymorphism - Same interface, different implementations
- Encapsulation - Bundling data and methods
- Abstraction - Hiding complex implementation details
Class
A class is a collection of objects. A class contains the blueprints or the prototype from which the objects are being created. It is a logical entity that contains some attributes and methods.
Class Syntax:
class ClassName:
# Class attributes
# Methods
Objects
Object is an entity that has a state and behavior associated with it. It may be any real-world object like a mouse, keyboard, chair, table, pen, etc.
Simple Class Example:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"Hi, I'm {self.name} and I'm {self.age} years old")
# Creating an object
person1 = Person("Surya", 23)
person1.introduce()
The self Parameter
Class methods must have an extra first parameter in the method definition. We do not give a value for this parameter when we call the method, Python provides it.
class Car:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def display_info(self):
print(f"This is a {self.brand} {self.model}")
car1 = Car("Toyota", "Camry")
car2 = Car("Honda", "Civic")
car1.display_info() # This is a Toyota Camry
car2.display_info() # This is a Honda Civic
Classes & Objects
Class and Instance Attributes
Class Attributes vs Instance Attributes:
class Student:
# Class attribute
school = "ABC High School"
total_students = 0
def __init__(self, name, grade):
# Instance attributes
self.name = name
self.grade = grade
Student.total_students += 1
def display_info(self):
print(f"Name: {self.name}, Grade: {self.grade}, School: {self.school}")
# Creating objects
student1 = Student("Alice", "A")
student2 = Student("Bob", "B")
student1.display_info()
student2.display_info()
print(f"Total students: {Student.total_students}")
print(f"School: {Student.school}")
Instance Methods, Class Methods, and Static Methods
class MathOperations:
pi = 3.14159
def __init__(self, number):
self.number = number
# Instance method
def square(self):
return self.number ** 2
# Class method
@classmethod
def circle_area(cls, radius):
return cls.pi * radius ** 2
# Static method
@staticmethod
def add(a, b):
return a + b
# Using the class
math_obj = MathOperations(5)
print(math_obj.square()) # 25
print(MathOperations.circle_area(3)) # 28.27431
print(MathOperations.add(10, 20)) # 30
Property Decorators
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@property
def area(self):
return 3.14159 * self._radius ** 2
@property
def circumference(self):
return 2 * 3.14159 * self._radius
# Using the class
circle = Circle(5)
print(f"Radius: {circle.radius}")
print(f"Area: {circle.area:.2f}")
print(f"Circumference: {circle.circumference:.2f}")
circle.radius = 7
print(f"New area: {circle.area:.2f}")
Special Methods (Magic Methods)
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return f"{self.title} by {self.author}"
def __repr__(self):
return f"Book('{self.title}', '{self.author}', {self.pages})"
def __len__(self):
return self.pages
def __eq__(self, other):
if isinstance(other, Book):
return self.title == other.title and self.author == other.author
return False
book1 = Book("1984", "George Orwell", 328)
book2 = Book("1984", "George Orwell", 328)
print(book1) # 1984 by George Orwell
print(repr(book1)) # Book('1984', 'George Orwell', 328)
print(len(book1)) # 328
print(book1 == book2) # True
Inheritance
It is the capability of one class to derive or inherit the properties from another class. The class that derives properties is called the derived class or child class and the class from which the properties are being derived is called the base class or parent class.
Benefits of Inheritance:
- It represents real-world relationships well.
- It provides the reusability of a code. We don't have to write the same code again and again. Also, it allows us to add more features to a class without modifying it.
- It is transitive in nature, which means that if class B inherits from another class A, then all the subclasses of B would automatically inherit from class A.
Single Inheritance
Example:
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def eat(self):
print(f"{self.name} is eating")
def sleep(self):
print(f"{self.name} is sleeping")
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, "Canine")
self.breed = breed
def bark(self):
print(f"{self.name} is barking")
# Creating an object
dog = Dog("Buddy", "Golden Retriever")
dog.eat() # Inherited method
dog.sleep() # Inherited method
dog.bark() # Dog-specific method
print(f"Name: {dog.name}, Species: {dog.species}, Breed: {dog.breed}")
Multiple Inheritance
class Flyable:
def fly(self):
print("Flying in the sky")
class Swimmable:
def swim(self):
print("Swimming in water")
class Duck(Animal, Flyable, Swimmable):
def __init__(self, name):
super().__init__(name, "Bird")
def quack(self):
print(f"{self.name} is quacking")
# Creating an object
duck = Duck("Donald")
duck.eat() # From Animal
duck.fly() # From Flyable
duck.swim() # From Swimmable
duck.quack() # Duck-specific method
Method Overriding
class Vehicle:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def start(self):
print("Vehicle is starting")
def stop(self):
print("Vehicle is stopping")
class Car(Vehicle):
def start(self):
print("Car engine is starting with a key")
class ElectricCar(Vehicle):
def start(self):
print("Electric car is starting silently")
# Creating objects
regular_car = Car("Toyota", "Camry")
electric_car = ElectricCar("Tesla", "Model 3")
regular_car.start() # Car engine is starting with a key
electric_car.start() # Electric car is starting silently
super() Function
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"I'm {self.name}, {self.age} years old")
class Student(Person):
def __init__(self, name, age, student_id):
super().__init__(name, age) # Call parent constructor
self.student_id = student_id
def introduce(self):
super().introduce() # Call parent method
print(f"My student ID is {self.student_id}")
student = Student("Surya", 20, "S12345")
student.introduce()
Polymorphism
Polymorphism means "many forms". In programming, it refers to the ability of a single interface to represent different underlying data types or classes.
Method Overriding (Runtime Polymorphism)
class Shape:
def area(self):
pass
def perimeter(self):
pass
class Rectangle(Shape):
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * (self.length + self.width)
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
# Polymorphism in action
shapes = [Rectangle(5, 4), Circle(3), Rectangle(2, 6)]
for shape in shapes:
print(f"Area: {shape.area():.2f}")
print(f"Perimeter: {shape.perimeter():.2f}")
print("-" * 20)
Duck Typing
class Dog:
def make_sound(self):
return "Woof!"
class Cat:
def make_sound(self):
return "Meow!"
class Cow:
def make_sound(self):
return "Moo!"
def animal_sound(animal):
# Duck typing: if it has make_sound method, it's good to go
return animal.make_sound()
animals = [Dog(), Cat(), Cow()]
for animal in animals:
print(animal_sound(animal))
Operator Overloading
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 3)
v2 = Vector(1, 4)
v3 = v1 + v2 # Uses __add__
v4 = v1 - v2 # Uses __sub__
v5 = v1 * 3 # Uses __mul__
print(v3) # Vector(3, 7)
print(v4) # Vector(1, -1)
print(v5) # Vector(6, 9)
Polymorphism with Built-in Functions
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
def __len__(self):
return abs(int(self.celsius))
def __str__(self):
return f"{self.celsius}°C"
temperatures = [Temperature(25), Temperature(-10), Temperature(0)]
for temp in temperatures:
print(f"Temperature: {temp}")
print(f"Length: {len(temp)}") # Uses __len__
print("-" * 15)
Encapsulation
Encapsulation is the bundling of data and methods that work on that data within one unit (class). It also restricts direct access to some of an object's components, which is a means of preventing accidental interference and misuse.
Access Modifiers in Python
- Public: Accessible from anywhere (default)
- Protected: Indicated by single underscore (_), intended for internal use
- Private: Indicated by double underscore (__), name mangling applied
Example of Access Modifiers:
class BankAccount:
def __init__(self, account_number, balance):
self.account_number = account_number # Public
self._bank_name = "ABC Bank" # Protected
self.__balance = balance # Private
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"Deposited ${amount}. New balance: ${self.__balance}")
else:
print("Invalid deposit amount")
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"Withdrew ${amount}. New balance: ${self.__balance}")
else:
print("Invalid withdrawal amount or insufficient funds")
def get_balance(self):
return self.__balance
def _internal_process(self):
print("Internal bank processing...")
# Using the class
account = BankAccount("12345", 1000)
# Public access
print(account.account_number) # 12345
# Protected access (convention, still accessible)
print(account._bank_name) # ABC Bank
# Private access (name mangling occurs)
# print(account.__balance) # This would cause an AttributeError
# Accessing private through methods
print(account.get_balance()) # 1000
account.deposit(500)
account.withdraw(200)
Property Decorators for Encapsulation
class Employee:
def __init__(self, name, salary):
self.name = name
self.__salary = salary
@property
def salary(self):
return self.__salary
@salary.setter
def salary(self, value):
if value < 0:
raise ValueError("Salary cannot be negative")
if value > 1000000:
raise ValueError("Salary too high, please verify")
self.__salary = value
@property
def annual_salary(self):
return self.__salary * 12
def __str__(self):
return f"Employee: {self.name}, Salary: ${self.__salary}"
# Using the class
emp = Employee("John Doe", 5000)
print(emp) # Employee: John Doe, Salary: $5000
# Using property getter
print(f"Monthly salary: ${emp.salary}")
print(f"Annual salary: ${emp.annual_salary}")
# Using property setter
emp.salary = 5500
print(f"Updated salary: ${emp.salary}")
# This would raise an error
# emp.salary = -1000
Data Validation through Encapsulation
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
@property
def length(self):
return self.__length
@length.setter
def length(self, value):
if value <= 0:
raise ValueError("Length must be positive")
self.__length = value
@property
def width(self):
return self.__width
@width.setter
def width(self, value):
if value <= 0:
raise ValueError("Width must be positive")
self.__width = value
@property
def area(self):
return self.__length * self.__width
@property
def perimeter(self):
return 2 * (self.__length + self.__width)
# Using the class
rect = Rectangle(5, 3)
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
rect.length = 7
print(f"New area: {rect.area}")
# This would raise an error
# rect.width = -2
Abstraction
Abstraction is the process of hiding the complex implementation details while showing only the essential features of an object. It allows you to focus on what an object does rather than how it does it.
Abstract Base Classes (ABC)
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
def description(self):
return "This is a geometric shape"
class Rectangle(Shape):
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * (self.length + self.width)
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
# Cannot instantiate abstract class
# shape = Shape() # This would raise TypeError
# Can instantiate concrete classes
rectangle = Rectangle(5, 4)
circle = Circle(3)
print(f"Rectangle area: {rectangle.area()}")
print(f"Circle area: {circle.area():.2f}")
print(rectangle.description())
print(circle.description())
Interface-like Behavior
from abc import ABC, abstractmethod
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
class Movable(ABC):
@abstractmethod
def move(self, x, y):
pass
class Button(Drawable, Movable):
def __init__(self, text, x=0, y=0):
self.text = text
self.x = x
self.y = y
def draw(self):
print(f"Drawing button '{self.text}' at ({self.x}, {self.y})")
def move(self, x, y):
self.x = x
self.y = y
print(f"Button moved to ({self.x}, {self.y})")
class Icon(Drawable, Movable):
def __init__(self, image, x=0, y=0):
self.image = image
self.x = x
self.y = y
def draw(self):
print(f"Drawing icon '{self.image}' at ({self.x}, {self.y})")
def move(self, x, y):
self.x = x
self.y = y
print(f"Icon moved to ({self.x}, {self.y})")
# Using the classes
button = Button("Click Me", 10, 20)
icon = Icon("home.png", 50, 60)
button.draw()
button.move(15, 25)
icon.draw()
icon.move(55, 65)
Real-world Example: Payment System
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount):
pass
@abstractmethod
def verify_payment(self, transaction_id):
pass
def log_transaction(self, amount, status):
print(f"Transaction logged: ${amount} - {status}")
class CreditCardProcessor(PaymentProcessor):
def process_payment(self, amount):
print(f"Processing credit card payment of ${amount}")
# Complex credit card processing logic here
return "CC_" + str(hash(amount))
def verify_payment(self, transaction_id):
print(f"Verifying credit card transaction: {transaction_id}")
return True
class PayPalProcessor(PaymentProcessor):
def process_payment(self, amount):
print(f"Processing PayPal payment of ${amount}")
# Complex PayPal processing logic here
return "PP_" + str(hash(amount))
def verify_payment(self, transaction_id):
print(f"Verifying PayPal transaction: {transaction_id}")
return True
class BankTransferProcessor(PaymentProcessor):
def process_payment(self, amount):
print(f"Processing bank transfer of ${amount}")
# Complex bank transfer logic here
return "BT_" + str(hash(amount))
def verify_payment(self, transaction_id):
print(f"Verifying bank transfer: {transaction_id}")
return True
# Payment system that works with any payment processor
class PaymentSystem:
def __init__(self, processor: PaymentProcessor):
self.processor = processor
def make_payment(self, amount):
transaction_id = self.processor.process_payment(amount)
if self.processor.verify_payment(transaction_id):
self.processor.log_transaction(amount, "SUCCESS")
return True
else:
self.processor.log_transaction(amount, "FAILED")
return False
# Using the system
credit_card_system = PaymentSystem(CreditCardProcessor())
paypal_system = PaymentSystem(PayPalProcessor())
bank_system = PaymentSystem(BankTransferProcessor())
credit_card_system.make_payment(100)
print("-" * 40)
paypal_system.make_payment(150)
print("-" * 40)
bank_system.make_payment(200)
Template Method Pattern
from abc import ABC, abstractmethod
class DataProcessor(ABC):
def process(self):
"""Template method defining the algorithm structure"""
data = self.read_data()
processed_data = self.process_data(data)
self.save_data(processed_data)
@abstractmethod
def read_data(self):
pass
@abstractmethod
def process_data(self, data):
pass
@abstractmethod
def save_data(self, data):
pass
class CSVProcessor(DataProcessor):
def read_data(self):
print("Reading data from CSV file")
return "csv_data"
def process_data(self, data):
print(f"Processing CSV data: {data}")
return f"processed_{data}"
def save_data(self, data):
print(f"Saving processed data to CSV: {data}")
class JSONProcessor(DataProcessor):
def read_data(self):
print("Reading data from JSON file")
return "json_data"
def process_data(self, data):
print(f"Processing JSON data: {data}")
return f"processed_{data}"
def save_data(self, data):
print(f"Saving processed data to JSON: {data}")
# Using the processors
csv_processor = CSVProcessor()
json_processor = JSONProcessor()
print("CSV Processing:")
csv_processor.process()
print("\nJSON Processing:")
json_processor.process()
- Reduces complexity by hiding implementation details
- Provides a clear contract for subclasses
- Enables code reusability and maintainability
- Supports polymorphism and loose coupling
Comments in Python
Comments are used to describe the code during development. We might wish to take notes on why a section of code exists for future reference.
Types of Comments
1. Single-line Comments
Example:
2. Multi-line Comments
Example:
3. Docstrings
Example:
In Python, multi-line comments are typically written using triple quotes (
'''or""") and must follow immediately after a definition to be used as documentation.