Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
24 views

Advance Python

The document discusses several topics related to Python programming including using an integrated development environment to write Python code, basic coding skills for beginners, working with data types and variables, and working with numeric and string data. It provides examples and explanations of concepts like using an IDE, debugging, reading documentation, version control, data types, variables, arithmetic operations, and more.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views

Advance Python

The document discusses several topics related to Python programming including using an integrated development environment to write Python code, basic coding skills for beginners, working with data types and variables, and working with numeric and string data. It provides examples and explanations of concepts like using an IDE, debugging, reading documentation, version control, data types, variables, arithmetic operations, and more.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 57

Chapter 1

Introduction to Python
1. Use IDE to develop Programs – Here's a simple example of how you can use an
Integrated Development Environment (IDE) like PyCharm to develop a Python program:
1. Install PyCharm: If you haven't already, download and install PyCharm from the JetBrains
website.
2. Create a New Project: Open PyCharm and create a new project by selecting "File" > "New
Project" from the menu. Choose a location for your project and select a Python interpreter.
3. Create a New Python File: Right-click on your project folder in the Project Explorer pane
and select "New" > "Python File". Give your file a name, such as "hello_world.py".
4. Write Your Python Code: Open the newly created Python file in the editor pane and write
your Python code. For example, you can write a simple "Hello, World!" program:
print("Hello, World!")

5. Run Your Program: To run your program, simply right-click anywhere in the editor pane
and select "Run 'hello_world'". Alternatively, you can use the keyboard shortcut (usually
Ctrl + Shift + F10).
6. View Output: You should see the output of your program in the "Run" tool window at the
bottom of the PyCharm interface.
7. Debugging: PyCharm also provides powerful debugging features. You can set breakpoints
in your code by clicking in the left margin of the editor pane, and then run your program in
debug mode by selecting "Debug 'hello_world'".
8. Explore Features: PyCharm offers many other features to enhance your development
workflow, such as code completion, version control integration, code refactoring, and more.
Take some time to explore the IDE and discover what works best for you.
That's it! You've now developed and run a Python program using PyCharm. Repeat these steps to
create more complex programs and explore the full capabilities of the IDE.
________________________________________________________________________________

2. Basic coding skills - Here are some basic coding skills that are essential for beginners:

1. Understanding Basic Syntax: Learn the syntax rules of the programming language you are
learning (e.g., Python, JavaScript, Java). Understand concepts like variables, data types,
operators, conditionals, loops, functions, and classes.
2. Problem Solving: Practice solving simple problems using your chosen programming
language. Start with small challenges and gradually increase the complexity as you improve.
3. Debugging: Learn how to debug your code when you encounter errors. Use print
statements, debugging tools provided by your IDE, or online debuggers to identify and fix
issues in your code.
4. Reading Documentation: Get comfortable reading documentation for libraries and
frameworks you use. Understand how to find information about functions, classes,
parameters, and usage examples.
5. Version Control: Learn the basics of version control systems like Git. Understand concepts
like repositories, commits, branches, and merges. Practice using Git commands to manage
your codebase.
6. Code Organization: Learn how to organize your code into logical units like functions,
modules, and packages. Follow best practices for naming conventions, commenting, and
documentation.
7. Testing: Understand the importance of testing your code to ensure it behaves as expected.
Learn how to write and run unit tests, integration tests, and other types of tests to verify your
code's correctness.
8. Reading and Writing Files: Learn how to read data from files and write data to files using
your programming language's file I/O capabilities.
9. Understanding Algorithms and Data Structures: Familiarize yourself with common
algorithms and data structures like arrays, linked lists, stacks, queues, sorting algorithms,
and searching algorithms. Understand how to implement and use them in your code.
10.Practice, Practice, Practice: The key to improving your coding skills is practice. Work on
coding challenges, participate in coding competitions, contribute to open-source projects,
and build your own projects to apply what you've learned.
Remember, coding is a skill that takes time and effort to develop. Be patient with yourself, keep
practicing, and don't be afraid to ask for help when you need it. With persistence and dedication,
you'll continue to improve and become a proficient programmer.

________________________________________________________________________________

3. Working with Data Types and variables - Working with data types and
variables is fundamental in programming. Here's a basic overview of how to work with them:
1. Data Types: Programming languages support various data types, such as integers, floats,
strings, booleans, lists, tuples, dictionaries, etc. Each data type represents different kinds of
values and has specific operations associated with it.
2. Variables: Variables are used to store and manipulate data in a program. You can assign
values to variables using the assignment operator (=). Variable names should be descriptive
and follow naming conventions (e.g., start with a letter or underscore, cannot contain spaces,
etc.).
3. Assigning Values: You can assign values to variables using the assignment operator (=). For
example:
# Assigning values to variables
x = 10
name = "John"
is_valid = True

4. Data Type Conversion: You can convert data from one type to another using type
conversion functions (e.g., int(), float(), str()). For example:
# Converting data types
num_str = "10"
num_int = int(num_str)

5. Working with Strings: Strings are sequences of characters enclosed in single or double
quotes. You can perform various operations on strings, such as concatenation, slicing,
formatting, etc.
# Working with strings
name = "John"
greeting = "Hello, " + name + "!"
print(greeting)

# Slicing strings
message = "Hello, World!"
substring = message[7:]
print(substring) # Output: World!

6. Mathematical Operations: You can perform mathematical operations on numeric data


types (integers, floats), such as addition, subtraction, multiplication, division, etc.
# Mathematical operations
x = 10
y = 5
sum = x + y
difference = x - y
product = x * y
quotient = x / y

7. Boolean Operations: Boolean data types (True or False) are used to represent logical
values. You can perform boolean operations such as AND, OR, NOT, etc.
# Boolean operations
is_valid = True
is_invalid = not is_valid

8. Lists and Arrays: Lists and arrays are used to store collections of data. You can access,
modify, and manipulate elements in lists using index notation.
# Working with lists
numbers = [1, 2, 3, 4, 5]
first_number = numbers[0]
numbers.append(6)

9. Dictionaries: Dictionaries are collections of key-value pairs. You can access and manipulate
values in dictionaries using keys.
# Working with dictionaries
person = {"name": "John", "age": 30, "city": "New York"}
print(person["name"]) # Output: John
These are just some basic concepts for working with data types and variables in programming. As
you continue learning, you'll encounter more advanced topics and techniques for working with data
in your programs.
________________________________________________________________________________
4. Working with numeric data & string data - Working with numeric data is
essential in programming, especially for performing mathematical calculations and data analysis.
Here are some key concepts and operations related to working with numeric data:
1. Numeric Data Types: Programming languages typically support various numeric data
types, such as integers (int), floating-point numbers (float), and sometimes other specialized
types like complex numbers. Integers represent whole numbers, while floating-point
numbers represent numbers with fractional parts.
2. Arithmetic Operations: You can perform basic arithmetic operations on numeric data
types, including addition, subtraction, multiplication, and division.
# Arithmetic operations
x = 10
y = 5
sum = x + y
difference = x - y
product = x * y
quotient = x / y

3. Integer Division and Modulo: Integer division (//) returns the quotient of a division
operation, discarding any fractional part, while the modulo operator (%) returns the
remainder of a division operation.
# Integer division and modulo
quotient = 10 // 3 # Output: 3
remainder = 10 % 3 # Output: 1

4. Exponentiation: Exponentiation (raising a number to a power) is performed using the **


operator.
# Exponentiation
result = 2 ** 3 # Output: 8

5. Math Module: Most programming languages provide a math module or library with
functions for more advanced mathematical operations, such as trigonometric functions,
logarithms, square roots, etc. These functions need to be imported before use.
# Using math module
import math

square_root = math.sqrt(25) # Output: 5.0


cosine = math.cos(math.pi) # Output: -1.0

6. Numeric Comparisons: You can compare numeric values using comparison operators like
==, !=, <, >, <=, and >=. These operators return boolean values (True or False) based on the
comparison result.
# Numeric comparisons
x = 10
y = 5
is_greater = x > y # Output: True
7. Type Conversion: You can convert numeric values between different data types using type
conversion functions like int(), float(), and str().
# Type conversion
num_str = "10"
num_int = int(num_str)

These are some of the fundamental concepts and operations involved in working with numeric data
in programming. As you progress, you'll encounter more advanced topics and techniques for
handling numeric data in various contexts.

String data - Working with string data is a fundamental aspect of programming, as strings
are used to represent text-based information. Here are some key concepts and operations related to
working with string data:
1. String Data Type: In most programming languages, strings are sequences of characters
enclosed in either single ('') or double ("") quotes. Strings can contain letters, numbers,
symbols, and whitespace.
# String data type
name = "John Doe"
message = 'Hello, World!'

2. String Concatenation: You can concatenate (combine) strings using the + operator.
# String concatenation
greeting = "Hello, " + name + "!"

3. String Indexing and Slicing: Strings can be indexed and sliced to access individual
characters or substrings.
# String indexing and slicing
message = "Hello, World!"
first_char = message[0] # Output: 'H'
substring = message[7:12] # Output: 'World'

4. String Length: You can find the length of a string using the len() function.
# String length
length = len(message) # Output: 13

5. String Methods: Most programming languages provide built-in methods for manipulating
strings, such as converting case, replacing substrings, splitting strings into lists, joining lists
into strings, and more.
# String methods
name_upper = name.upper() # Output: 'JOHN DOE'
message_replace = message.replace('Hello', 'Hi') # Output: 'Hi, World!'
words = message.split(',') # Output: ['Hello', ' World!']

6. String Formatting: String formatting allows you to create formatted strings with
placeholders for variable values. There are various methods for string formatting, including
%-formatting, str.format(), and f-strings (formatted string literals).
# String formatting with f-strings (Python 3.6+)
name = "John"
age = 30
formatted_string = f"My name is {name} and I am {age} years old."
7. Escape Characters: Escape characters are special characters preceded by a backslash () that
represent non-printable characters or special formatting in strings.
# Escape characters
escaped_string = "This is a \"quoted\" string."
newline_string = "This is\na newline."

These are some of the fundamental concepts and operations involved in working with string data in
programming. Strings are versatile and widely used, so mastering string manipulation techniques is
essential for any programmer.

________________________________________________________________________________
5. Python functions - Functions in Python are blocks of reusable code that perform a
specific task. They allow you to break down your code into smaller, more manageable pieces,
making it easier to read, understand, and maintain. Here are the key concepts related to Python
functions:
1. Function Definition: Functions are defined using the def keyword followed by the
function name and parentheses containing optional parameters.
def greet(name):
print(f"Hello, {name}!")

2. Function Call: To execute a function and run its code, you need to call it by using its name
followed by parentheses.
greet("John")

3. Parameters and Arguments: Parameters are placeholders for values that a function expects
to receive, while arguments are the actual values passed to the function during the function
call.
def add(x, y):
return x + y

result = add(5, 3) # x=5, y=3

4. Return Statement: Functions can return a value using the return statement. This value
can then be used in other parts of your code.
def multiply(x, y):
return x * y

result = multiply(4, 6) # result = 24

5. Default Parameters: You can provide default values for parameters in a function definition.
If a value is not provided during the function call, the default value is used.
def greet(name="World"):
print(f"Hello, {name}!")

greet() # Output: Hello, World!


greet("John") # Output: Hello, John!
6. Keyword Arguments: You can pass arguments to a function by explicitly specifying the
parameter names along with their values. This allows you to pass arguments in any order,
regardless of the order of parameters in the function definition.
def greet(first_name, last_name):
print(f"Hello, {first_name} {last_name}!")

greet(last_name="Doe", first_name="John") # Output: Hello, John Doe!

7. Variable Number of Arguments: You can define functions that accept a variable number of
arguments using *args and **kwargs parameters.
def sum_values(*args):
return sum(args)

result = sum_values(1, 2, 3, 4, 5) # result = 15

8. Docstrings: Docstrings are used to provide documentation for functions. They are enclosed
in triple quotes and describe what the function does, its parameters, and its return value.
def greet(name):
"""
Greets the user with the given name.
"""
print(f"Hello, {name}!")

9. Scope: Variables defined inside a function have local scope and are only accessible within
that function. Variables defined outside any function have global scope and can be accessed
from anywhere in the code.
def my_function():
x = 10 # Local variable
print(x)

my_function() # Output: 10

10.Lambda Functions: Lambda functions (also known as anonymous functions) are small,
inline functions that can have any number of parameters but only one expression. They are
defined using the lambda keyword.
add = lambda x, y: x + y
result = add(3, 5) # result = 8

These are the basic concepts and features of functions in Python. Functions are powerful tools for
organizing code and making it more modular, reusable, and maintainable.

________________________________________________________________________________
6. Boolean expressions - Boolean expressions in Python are expressions that evaluate to
either True or False. They are commonly used in conditional statements (if, elif, else) and loops to
control the flow of a program based on certain conditions. Here are some key points about boolean
expressions:
1. Comparison Operators: Comparison operators are used to compare values. They include:
• Equal to (==)
• Not equal to (!=)
• Greater than (>)
• Greater than or equal to (>=)
• Less than (<)
• Less than or equal to (<=)
x = 5
y = 10

# Comparison operators
print(x == y) # False
print(x != y) # True
print(x > y) # False
print(x < y) # True
print(x >= y) # False
print(x <= y) # True

2. Logical Operators: Logical operators are used to combine multiple boolean expressions.
They include:
• Logical AND (and)
• Logical OR (or)
• Logical NOT (not)
a = True
b = False

# Logical operators
print(a and b) # False
print(a or b) # True
print(not a) # False

3. Membership Operators: Membership operators are used to test if a value is present in a


sequence (such as a list, tuple, or string). They include:
• in: Returns True if the value is present in the sequence.
• not in: Returns True if the value is not present in the sequence.
my_list = [1, 2, 3, 4, 5]

# Membership operators
print(3 in my_list) # True
print(6 not in my_list) # True

4. Identity Operators: Identity operators are used to compare the memory location of two
objects. They include:
• is: Returns True if both variables point to the same object.
• is not: Returns True if both variables do not point to the same object.
x = [1, 2, 3]
y = [1, 2, 3]

# Identity operators
print(x is y) # False
print(x is not y) # True
5. Short-Circuit Evaluation: Python's logical operators (and and or) use short-circuit
evaluation. This means that they stop evaluating expressions as soon as the result is known.
x = 5
y = 10

# Short-circuit evaluation
result = (x > 0) and (y < 5) # Since (x > 0) is False, (y < 5) is not
evaluated
print(result) # False

Boolean expressions are fundamental in programming as they enable you to make decisions and
control the flow of your code based on conditions. Understanding how to use them effectively is
essential for writing efficient and readable code.

________________________________________________________________________________
7. Selection structure - Selection structures, also known as conditional statements, are
used in programming to execute different blocks of code based on certain conditions. In Python, the
main types of selection structures are the if statement, the if-else statement, and the if-elif-else
statement. Here's an overview of each:
1. if Statement: The if statement allows you to execute a block of code only if a specified
condition is true.
x = 10
if x > 5:
print("x is greater than 5")

2. if-else Statement: The if-else statement allows you to execute one block of code if the
condition is true, and another block of code if the condition is false.
x = 3
if x % 2 == 0:
print("x is even")
else:
print("x is odd")

3. if-elif-else Statement: The if-elif-else statement allows you to check multiple conditions
and execute different blocks of code based on the first condition that evaluates to true. The
elif (short for "else if") keyword is used to check additional conditions.
x = 0
if x > 0:
print("x is positive")
elif x < 0:
print("x is negative")
else:
print("x is zero")

4. Nested if Statements: You can also nest if statements within each other to create more
complex conditions.
x = 10
if x > 0:
if x % 2 == 0:
print("x is positive and even")
else:
print("x is positive and odd")
else:
print("x is non-positive")

5. Ternary Conditional Operator: Python also supports a ternary conditional operator, which
provides a compact way to write if-else statements in a single line.
x = 10
result = "Even" if x % 2 == 0 else "Odd"
print(result)

Selection structures are essential for controlling the flow of your program based on different
conditions, allowing your code to make decisions and respond dynamically to changing situations.
Understanding how to use if statements and their variations effectively is fundamental for writing
robust and flexible code.

________________________________________________________________________________
8. Iteration structure - Iteration structures, also known as loops, are used in programming
to execute a block of code repeatedly until a certain condition is met. In Python, there are two main
types of iteration structures: the for loop and the while loop. Here's an overview of each:
1. for Loop: The for loop is used to iterate over a sequence (such as a list, tuple, string, or
range) and execute a block of code for each element in the sequence.
# Iterate over a list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)

# Iterate over a string


for char in "Python":
print(char)

# Iterate over a range of numbers


for i in range(5):
print(i)

2. while Loop: The while loop is used to repeatedly execute a block of code as long as a
specified condition is true. Be cautious, as if the condition never becomes false, it can lead
to an infinite loop.
# Print numbers from 0 to 4 using a whileloop
i = 0
while i < 5:
print(i)
i += 1

3. break Statement: The break statement is used to exit the loop prematurely, regardless of
the loop condition.
# Stop the loop when reaching a certain condition
for i in range(10):
print(i)
if i == 5:
break
4. continue Statement: The continue statement is used to skip the rest of the loop's code
block for the current iteration and proceed to the next iteration.
# Skip printing even numbers
for i in range(10):
if i % 2 == 0:
continue
print(i)

5. else Clause: Both for and while loops can have an optional else clause, which is
executed when the loop completes normally (i.e., without encountering a break statement).
# Find prime numbers
for num in range(2, 10):
for i in range(2, num):
if num % i == 0:
print(f"{num} is not a prime number")
break
else:
print(f"{num} is a prime number")

Iteration structures are fundamental in programming as they allow you to automate repetitive tasks
and process data efficiently. By mastering for and while loops and understanding when to use
them, you can write more concise and powerful code.

________________________________________________________________________________
9. Working with lists - Working with lists in Python is fundamental, as lists are versatile
data structures that can store multiple items in a single variable. Here are some common operations
and techniques for working with lists:
1. Creating Lists: You can create lists by enclosing comma-separated values within square
brackets [].
# Create a list of numbers
numbers = [1, 2, 3, 4, 5]

# Create a list of strings


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

2. Accessing Elements: You can access individual elements of a list using indexing. Python
uses zero-based indexing, where the first element is at index 0.
print(fruits[0]) # Output: "apple"
print(numbers[2]) # Output: 3

3. Slicing Lists: You can extract a subset of elements from a list using slicing. Slicing syntax is
list[start:stop:step].
print(numbers[1:4]) # Output: [2, 3, 4]
print(fruits[:2]) # Output: ["apple", "banana"]
print(numbers[::2]) # Output: [1, 3, 5]

4. Modifying Lists: Lists are mutable, meaning you can change their elements after they are
created.
fruits[0] = "orange" # Update the first element
numbers.append(6) # Add an element to the end
del fruits[1] # Delete an element

5. List Methods: Python provides built-in methods for performing common operations on
lists, such as adding, removing, sorting, and searching.
numbers.append(6) # Add an element to the end
fruits.insert(1, "banana") # Insert an element at a specific index
fruits.remove("cherry") # Remove a specific element
fruits.sort() # Sort the list in ascending order
index = fruits.index("banana") # Find the index of an element

6. Iterating Over Lists: You can use loops to iterate over the elements of a list.
for fruit in fruits:
print(fruit)

7. List Comprehensions: List comprehensions provide a concise way to create lists.


squares = [x ** 2 for x in range(1, 6)] # [1, 4, 9, 16, 25]
even_numbers = [x for x in numbers if x % 2 == 0]

8. Copying Lists: Be careful when copying lists. Using the assignment operator = creates a
reference to the original list, so modifying one list will affect the other. Use slicing or the
copy() method to create a separate copy.
original_list = [1, 2, 3]
copied_list = original_list[:] # or original_list.copy()

Working with lists is essential in Python programming, as they provide a flexible way to store and
manipulate data. By mastering list operations and techniques, you can write more efficient and
expressive code.

________________________________________________________________________________
10. Work with a list of lists - Working with a list of lists in Python allows you to
represent and manipulate two-dimensional data structures, such as matrices or tables. Here's how
you can work with a list of lists:
1. Creating a List of Lists: You can create a list of lists by nesting square brackets []. Each
inner list represents a row, and the outer list contains all the rows.
# Create a list of lists (2D matrix)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]

2. Accessing Elements: You can access individual elements of a list of lists using double
indexing. The first index accesses the row, and the second index accesses the column.
print(matrix[0][1]) # Access element at row 0, column 1 (output: 2)

3. Iterating Over a List of Lists: You can use nested loops to iterate over the elements of a list
of lists.
for row in matrix:
for element in row:
print(element)

4. Modifying Elements: Lists of lists are mutable, so you can modify individual elements as
needed.
matrix[1][1] = 10 # Modify element at row 1, column 1

5. Adding and Removing Rows: You can add or remove entire rows from a list of lists using
list methods.
# Add a new row
new_row = [10, 11, 12]
matrix.append(new_row)

# Remove a row
del matrix[1] # Remove the second row

6. Copying a List of Lists: Be cautious when copying a list of lists, as using the assignment
operator = creates a shallow copy. Modifying one list will affect the other. To create a deep
copy, use list comprehension or the copy module.
# Shallow copy
copied_matrix = matrix[:]

# Deep copy
import copy
copied_matrix = copy.deepcopy(matrix)

Working with a list of lists allows you to represent complex data structures and perform various
operations on them efficiently. By understanding how to manipulate nested lists, you can handle
two-dimensional data effectively in Python.

________________________________________________________________________________
11. Work with tuples - Tuples in Python are similar to lists, but they are immutable,
meaning their elements cannot be changed after creation. Here's how you can work with tuples:
1. Creating Tuples: You can create a tuple by enclosing comma-separated values within
parentheses ().
# Create a tuple of numbers
numbers = (1, 2, 3, 4, 5)

# Create a tuple of strings


fruits = ("apple", "banana", "cherry")

2. Accessing Elements: You can access individual elements of a tuple using indexing. Python
uses zero-based indexing, where the first element is at index 0.
print(fruits[0]) # Output: "apple"
print(numbers[2]) # Output: 3

3. Slicing Tuples: You can extract a subset of elements from a tuple using slicing. Slicing
syntax is tuple[start:stop:step].
print(numbers[1:4]) # Output: (2, 3, 4)
print(fruits[:2]) # Output: ("apple", "banana")
print(numbers[::2]) # Output: (1, 3, 5)

4. Immutable Nature: Tuples are immutable, so you cannot modify their elements or size after
creation. Attempting to do so will result in an error.
# This will raise an error
fruits[0] = "orange"

5. Iterating Over Tuples: You can use loops to iterate over the elements of a tuple.
for fruit in fruits:
print(fruit)

6. Tuple Methods: Tuples have fewer methods compared to lists due to their immutability. The
count() and index() methods are commonly used.
count = numbers.count(3) # Count occurrences of a value
index = fruits.index("banana") # Find the index of a value

7. Tuple Packing and Unpacking: You can pack multiple values into a tuple or unpack a tuple
into multiple variables in a single line.
# Packing
coordinates = (3, 4)

# Unpacking
x, y = coordinates

Tuples are useful for representing fixed collections of items that should not be changed, such as
coordinates, constants, or database records. While they lack some of the flexibility of lists, their
immutability makes them safer and more efficient in certain situations.

________________________________________________________________________________
12. Work with dates and times - Working with dates and times in Python is made easy
by the datetime module. Here's how you can work with dates, times, and timedeltas:
1. Importing the datetime Module: First, import the datetime module to access its
functionality.
import datetime

2. Creating Date and Time Objects: You can create date objects, time objects, or datetime
objects using the constructors provided by the datetime module.
# Create a date object
today = datetime.date.today()
print(today) # Output: YYYY-MM-DD format

# Create a time object


current_time = datetime.time(12, 30, 0)
print(current_time) # Output: HH:MM:SS format

# Create a datetime object


now = datetime.datetime.now()
print(now) # Output: YYYY-MM-DD HH:MM:SS format
3. Formatting Dates and Times: You can format date and time objects into strings using the
strftime() method and specifying a format string.
formatted_date = today.strftime("%Y-%m-%d")
print(formatted_date) # Output: YYYY-MM-DD format

formatted_time = current_time.strftime("%H:%M:%S")
print(formatted_time) # Output: HH:MM:SS format

formatted_datetime = now.strftime("%Y-%m-%d %H:%M:%S")


print(formatted_datetime) # Output: YYYY-MM-DD HH:MM:SS format

4. Parsing Strings to Dates and Times: Conversely, you can parse strings into date, time, or
datetime objects using the strptime() function and specifying the format.
date_str = "2023-04-25"
parsed_date = datetime.datetime.strptime(date_str, "%Y-%m-%d")
print(parsed_date) # Output: 2023-04-25 00:00:00

5. Working with Timedeltas: Timedeltas represent the difference between two dates or times.
You can perform arithmetic operations with timedeltas.
# Calculate the difference between two dates
delta = datetime.timedelta(days=7)
next_week = today + delta
print(next_week) # Output: Date 7 days from now

# Calculate the difference between two datetimes


time_diff = now - parsed_date
print(time_diff) # Output: Timedelta object representing the difference

Working with dates and times is essential in many applications, such as scheduling tasks, logging
events, or performing time-based calculations. The datetime module provides powerful tools for
handling various aspects of date and time manipulation in Python.

________________________________________________________________________________
13. Get started with dictionaries - Dictionaries in Python are unordered collections of
key-value pairs. They are versatile data structures used to store and retrieve data efficiently. Here's
how you can get started with dictionaries:
1. Creating Dictionaries: You can create dictionaries by enclosing comma-separated key-
value pairs within curly braces {}.
# Create an empty dictionary
my_dict = {}

# Create a dictionary with initial key-value pairs


my_dict = {"name": "John", "age": 30, "city": "New York"}

2. Accessing Elements: You can access the value associated with a specific key using square
brackets [].
print(my_dict["name"]) # Output: "John"
print(my_dict["age"]) # Output: 30

3. Modifying Dictionaries: Dictionaries are mutable, so you can add, update, or remove key-
value pairs as needed.
# Add a new key-value pair
my_dict["gender"] = "Male"

# Update the value of an existing key


my_dict["age"] = 32

# Remove a key-value pair


del my_dict["city"]

4. Dictionary Methods: Python provides several built-in methods for working with
dictionaries.
# Get a list of all keys
keys = my_dict.keys()

# Get a list of all values


values = my_dict.values()

# Check if a key exists


exists = "name" in my_dict

# Get the value for a key, or a default value if the key doesn't exist
value = my_dict.get("name", "Default")

5. Iterating Over Dictionaries: You can iterate over the keys, values, or key-value pairs of a
dictionary using loops.
# Iterate over keys
for key in my_dict:
print(key)

# Iterate over values


for value in my_dict.values():
print(value)

# Iterate over key-value pairs


for key, value in my_dict.items():
print(key, ":", value)

6. Dictionary Comprehensions: Similar to list comprehensions, you can use dictionary


comprehensions to create dictionaries in a concise way.
# Create a dictionary from a list of tuples
pairs = [("a", 1), ("b", 2), ("c", 3)]
my_dict = {key: value for key, value in pairs}

Dictionaries are highly versatile and can be used to represent a wide range of data structures,
including mappings, configurations, and more. By mastering dictionary operations and techniques,
you can write more expressive and efficient Python code.

________________________________________________________________________________
Chapter 2
Classes in Pyhon

1. OOPS concepts -
In Python, object-oriented programming (OOP) is a programming paradigm that revolves around
the concept of "objects," which are instances of classes. OOP allows you to structure your code in a
more organized and modular way by encapsulating data (attributes) and behavior (methods) into
objects.
Here are the key OOP concepts in Python:
1. Class: A class is a blueprint for creating objects. It defines the attributes and methods that
the objects will have. Classes are defined using the class keyword.

2. Object (Instance): An object is an instance of a class. It represents a specific entity with its
own set of attributes and methods.
3. Attributes: Attributes are data associated with objects. They represent the state of the
object. Attributes can be variables that store data.
4. Methods: Methods are functions defined within a class. They define the behavior of the
objects. Methods can operate on the object's attributes and perform actions.
5. Inheritance: Inheritance is a mechanism where a class can inherit attributes and methods
from another class. The class that inherits is called a subclass or derived class, and the class
being inherited from is called a superclass or base class. It promotes code reusability and
establishes a parent-child relationship between classes.
6. Encapsulation: Encapsulation is the bundling of data (attributes) and methods that operate
on the data into a single unit (class). It hides the internal state of the object from the outside
world and only exposes necessary interfaces.
7. Polymorphism: Polymorphism allows objects of different classes to be treated as objects of
a common superclass. It enables methods to be invoked on objects without knowing their
specific types. Polymorphism is achieved through method overriding and method
overloading.
8. Abstraction: Abstraction is the process of hiding the implementation details of a class and
only exposing the necessary features to the user. It focuses on what an object does rather
than how it does it.
Ex. OOP in python
class Animal:
def __init__(self, name):
self.name = name

def sound(self):
pass

class Dog(Animal):
def sound(self):
return "Woof!"

class Cat(Animal):
def sound(self):
return "Meow!"

dog = Dog("Buddy")
print(dog.name) # Output: Buddy
print(dog.sound()) # Output: Woof!

cat = Cat("Whiskers")
print(cat.name) # Output: Whiskers
print(cat.sound()) # Output: Meow!
____________________________________________________________
2. Classes and Objects - In Python, classes and objects are fundamental concepts in
object-oriented programming (OOP). They allow you to create reusable and modular code by
organizing data (attributes) and behavior (methods) into objects.
Here's an overview of classes and objects in Python:

Classes:
• A class is a blueprint or template for creating objects.
• It defines the attributes (data) and methods (functions) that the objects will have.
• Classes are defined using the class keyword followed by the class name.
• Class names are typically written in CamelCase convention (e.g., MyClass).

Syntax
class ClassName:
# Constructor method
def __init__(self, param1, param2, ...):
self.attribute1 = param1
self.attribute2 = param2
...

# Other methods
def method1(self, ...):
# Method body
pass

Objects (Instances):
• An object is an instance of a class.
• It represents a specific entity with its own set of attributes and methods.
• Objects are created by calling the class constructor (the __init__ method).
• Multiple objects can be created from the same class, each with its own unique state.
Syntax

# Creating an object of ClassName


object_name = ClassName(param1, param2, ...)

Ex. - Example of class and objects

# Define a class
class Dog:
# Constructor method
def __init__(self, name, age):
self.name = name
self.age = age

# Method to display information


def display_info(self):
print(f"Name: {self.name}, Age: {self.age}")

# Create objects of the Dog class


dog1 = Dog("Buddy", 3)
dog2 = Dog("Max", 5)

# Access attributes and call methods of objects


print(dog1.name) # Output: Buddy
print(dog2.age) # Output: 5
dog1.display_info() # Output: Name: Buddy, Age: 3
dog2.display_info() # Output: Name: Max, Age: 5

In this example:
• Dog is a class with attributes name and age, and a method display_info.
• dog1 and dog2 are objects of the Dog class, representing individual dogs with their own
names and ages.
• We can access attributes and call methods of objects using dot notation
(object_name.attribute or object_name.method()).

____________________________________________________________

3. Constructors - In Python, a constructor is a special method used for initializing objects of


a class. It is called automatically when a new instance of the class is created. The constructor
method in Python is defined using the __init__() method.
Here's an overview of constructors in Python:

Constructor Method (__init__()):


• The __init__() method is a special method in Python classes used for initializing
objects.
• It is called automatically when a new instance of the class is created.
• The constructor method can accept parameters that are used to initialize the object's
attributes.
• Inside the constructor, you can initialize the object's attributes using the parameters passed to
the method.
• The first parameter of the __init__() method, conventionally named self, refers to the
current instance of the class.

Syntax:
class ClassName:
def __init__(self, param1, param2, ...):
self.attribute1 = param1
self.attribute2 = param2
...
Example:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age

# Creating objects of the Dog class


dog1 = Dog("Buddy", 3)
dog2 = Dog("Max", 5)

# Accessing attributes of objects


print(dog1.name) # Output: Buddy
print(dog2.age) # Output: 5

In this example:
• The Dog class has a constructor method __init__() that initializes the name and age
attributes of the Dog objects.
• When objects dog1 and dog2 are created, the __init__() method is automatically
called with the provided arguments.
• Inside the constructor, the name and age attributes of the objects are initialized using the
parameters passed to the method.

____________________________________________________________

4. Data Hiding - Data hiding in Python refers to the concept of encapsulating data within a
class such that it cannot be accessed directly from outside the class. This is achieved by prefixing
the attribute names with double underscores (__), making them private to the class. This practice is
also known as "name mangling."
Here's how data hiding works in Python:
1. Private Attributes: Attributes that are prefixed with double underscores (__) are considered
private to the class. They cannot be accessed directly from outside the class.
2. Name Mangling: When you prefix an attribute with double underscores, Python internally
changes its name to include the class name as a prefix. This is done to prevent name clashes
in subclasses.
3. Accessing Private Attributes: Although private attributes cannot be accessed directly from
outside the class, they can still be accessed indirectly using methods defined within the class
(e.g., getter and setter methods).
4. Getter and Setter Methods: Getter methods are used to access private attributes, and setter
methods are used to modify them. These methods provide controlled access to the private
data and allow for validation or additional logic to be applied.
Here's an example demonstrating data hiding in Python:
class MyClass:
def __init__(self):
self.__private_attr = 10 # Private attribute

def get_private_attr(self):
return self.__private_attr # Getter method
def set_private_attr(self, value):
if value >= 0:
self.__private_attr = value # Setter method

# Create an object of MyClass


obj = MyClass()

# Access private attribute using getter method


print(obj.get_private_attr()) # Output: 10

# Modify private attribute using setter method


obj.set_private_attr(20)

# Access private attribute again


print(obj.get_private_attr()) # Output: 20

In this example, __private_attr is a private attribute of the MyClass class. It can only be
accessed and modified using the get_private_attr() and set_private_attr()
methods, respectively. This encapsulation prevents direct access to the attribute from outside the
class, providing better control over the class's data.

____________________________________________________________
5. Instance Method - Instance methods in Python are functions defined within a class that
operate on instances of the class. These methods are associated with objects (instances) of the class
and can access and modify the object's attributes.
Here are the key characteristics of instance methods:
1. Defined within a Class: Instance methods are defined within the body of a class using the
def keyword.

2. Access Instance Attributes: Instance methods have access to the attributes of the object
(instance) they are called on using the self parameter.

3. Can Modify Object State: Instance methods can modify the state of the object by changing
the values of its attributes.
4. Useful for Encapsulation and Abstraction: Instance methods are commonly used to
encapsulate behavior associated with objects and implement the logic specific to the class.
5. Implicitly Pass self Parameter: When calling an instance method, Python automatically
passes the object itself as the first argument (self). This allows the method to access the
object's attributes and other methods.
Here's a simple example demonstrating instance methods in Python:
class Car:
def __init__(self, make, model):
self.make = make
self.model = model
self.odometer = 0

def drive(self, distance):


self.odometer += distance

def display_odometer(self):
print(f"Odometer reading: {self.odometer} miles")
# Create an object of the Car class
my_car = Car("Toyota", "Camry")

# Call instance methods on the object


my_car.drive(100)
my_car.display_odometer() # Output: Odometer reading: 100 miles

In this example:
• drive() and display_odometer() are instance methods of the Car class.
• drive() method increments the odometer attribute by the specified distance.
• display_odometer() method prints the current odometer reading of the car.
• Instance methods are called on the my_car object, which operates on the attributes of that
specific car instance.

____________________________________________________________

6. Special Methods - Special methods in Python, also known as magic methods or dunder
methods, are predefined methods with double underscores (__) at the beginning and end of their
names. These methods allow classes to emulate built-in Python behavior and enable customization
of object behavior in various contexts.
Here are some key points about special methods:
1. Automatic Invocation: Special methods are invoked implicitly by Python in response to
certain operations or built-in functions. For example, when you add two objects together
using the + operator, Python calls the __add__() method of the left operand.

2. Overriding Built-in Behavior: By implementing special methods in a class, you can


customize how instances of that class behave when they interact with built-in operators,
functions, or statements.
3. Conventional Names: Special method names follow a specific naming convention, often
starting and ending with double underscores. For example, __init__() is the constructor
method, __str__() is used to represent an object as a string, and __add__() is used to
define addition behavior.
4. Common Use Cases: Special methods are commonly used for tasks such as object
initialization (__init__()), string representation (__str__(), __repr__()),
arithmetic operations (__add__(), __sub__(), etc.), comparison (__eq__(),
__lt__(), etc.), and more.

5. Customizing Behavior: By implementing special methods in your classes, you can make
your objects behave like built-in types or define custom behavior for specific operations.
Here's an example demonstrating the use of a special method:
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 __str__(self):
return f"({self.x}, {self.y})"

# Create two Vector objects


v1 = Vector(1, 2)
v2 = Vector(3, 4)

# Add the vectors using the '+' operator


result = v1 + v2

# Print the result


print(result) # Output: (4, 6)

In this example:
• The Vector class defines the __add__() special method to customize the behavior of
the + operator for adding vectors.
• When v1 + v2 is executed, Python calls the __add__() method of the v1 object with
v2 as the argument.
• The __add__() method returns a new Vector object representing the sum of the two
vectors.

____________________________________________________________

7. Class Variables - Class variables in Python are variables that are shared among all
instances (objects) of a class. They are defined within the class but outside of any instance methods.
Class variables are accessed using the class name rather than through instances of the class.
Here are some key points about class variables:
1. Defined at Class Level: Class variables are declared at the top level of a class definition,
outside of any instance methods. They are typically initialized within the class body.
2. Shared Among Instances: Class variables are shared among all instances of the class. This
means that changes made to a class variable by one instance will affect all other instances.
3. Accessed via Class Name: Class variables are accessed using the class name followed by
the dot operator (.). They can also be accessed within instance methods using the self
parameter or directly using the class name.
4. Useful for Storing Shared Data: Class variables are useful for storing data that is shared
among all instances of a class, such as configuration settings, constants, or shared state.
5. Can be Accessed and Modified: Class variables can be accessed and modified both inside
and outside the class. However, it's important to be aware of the implications of modifying
class variables, as changes will affect all instances of the class.
Here's an example demonstrating the use of class variables in Python:
class Employee:
# Class variable
num_employees = 0

def __init__(self, name, salary):


self.name = name
self.salary = salary
# Increment the class variable
Employee.num_employees += 1

def display_info(self):
print(f"Name: {self.name}, Salary: {self.salary}")

# Create instances of the Employee class


emp1 = Employee("John", 50000)
emp2 = Employee("Alice", 60000)

# Access class variable using class name


print(Employee.num_employees) # Output: 2

# Modify class variable using class name


Employee.num_employees = 100

# Access class variable using instance


print(emp1.num_employees) # Output: 100
print(emp2.num_employees) # Output: 100

In this example:
• num_employees is a class variable that tracks the total number of employees.
• Every time an instance of the Employee class is created, the num_employees class
variable is incremented.
• Class variables can be accessed and modified using either the class name
(Employee.num_employees) or an instance of the class (emp1.num_employees).

____________________________________________________________

8. Inheritance - Inheritance is a fundamental concept in object-oriented programming


(OOP) that allows a class (called the child or subclass) to inherit attributes and methods from
another class (called the parent or superclass). This enables code reuse and facilitates the creation of
hierarchical relationships between classes.
Here are the key points about inheritance in Python:
1. Parent Class (Superclass): The class whose attributes and methods are inherited by another
class. It is also known as the superclass or base class.
2. Child Class (Subclass): The class that inherits attributes and methods from another class. It
is also known as the subclass or derived class.
3. Syntax: To create a subclass that inherits from a superclass, specify the superclass name in
parentheses after the subclass name in the class definition.
4. Method Overriding: Child classes can override methods of the parent class by defining
methods with the same name in the child class. This allows the child class to provide its own
implementation of the method.
5. Accessing Parent Class Methods: Child classes can access methods of the parent class
using the super() function.

6. Multiple Inheritance: Python supports multiple inheritance, which allows a subclass to


inherit from more than one superclass.
7. Inheritance Hierarchy: Inheritance relationships can form hierarchical structures, with
multiple levels of inheritance.
Here's an example demonstrating inheritance in Python:
# Parent class (Superclass)
class Animal:
def __init__(self, name):
self.name = name

def speak(self):
return "Unknown sound"

# Child class (Subclass) inheriting from Animal


class Dog(Animal):
def speak(self):
return "Woof!"

# Child class (Subclass) inheriting from Animal


class Cat(Animal):
def speak(self):
return "Meow!"

# Create instances of the child classes


dog = Dog("Buddy")
cat = Cat("Whiskers")

# Call the speak method of each instance


print(dog.name, "says:", dog.speak()) # Output: Buddy says: Woof!
print(cat.name, "says:", cat.speak()) # Output: Whiskers says: Meow!

In this example:
• Animal is the parent class with an speak() method.
• Dog and Cat are child classes that inherit from Animal.
• Each child class overrides the speak() method with its own implementation.
• Instances of Dog and Cat can call the speak() method, which provides the appropriate
sound for each animal.

____________________________________________________________

9. Polymorphism - Polymorphism is a core concept in object-oriented programming that


allows objects to be treated as instances of their parent class, even when they are actually instances
of a subclass. It enables flexibility and code reuse by allowing methods to operate on objects of
different types through a common interface.
Here are the key points about polymorphism in Python:
1. Method Overriding: Polymorphism is often achieved through method overriding, where a
method defined in the superclass is redefined in a subclass with the same name and
signature. This allows different subclasses to provide their own implementations of the
method.
2. Common Interface: Polymorphism relies on objects sharing a common interface, such as a
method or attribute, that can be used to interact with objects of different types.
3. Dynamic Binding: In languages like Python, method calls are resolved dynamically at
runtime based on the type of the object being operated on. This allows methods to be
invoked on objects of different classes, as long as they support the required interface.
4. Flexibility and Extensibility: Polymorphism allows code to be written in a generic way that
can operate on a wide range of objects without needing to know their specific types. This
makes the code more flexible and extensible.
5. Example: A common example of polymorphism is the len() function in Python, which
can be used to get the length of a variety of objects, including strings, lists, tuples, and
dictionaries.
Here's a simple example demonstrating polymorphism in Python:
class Animal:
def speak(self):
pass

class Dog(Animal):
def speak(self):
return "Woof!"

class Cat(Animal):
def speak(self):
return "Meow!"

# Function that takes an Animal object and calls its speak method
def make_sound(animal):
return animal.speak()

# Create instances of Dog and Cat


dog = Dog()
cat = Cat()

# Call the make_sound function with different types of animals


print(make_sound(dog)) # Output: Woof!
print(make_sound(cat)) # Output: Meow!

In this example:
• The Animal class defines a speak() method, which is overridden in the Dog and Cat
subclasses.
• The make_sound() function takes an Animal object as an argument and calls its
speak() method.
• Even though make_sound() is called with objects of different subclasses (Dog and Cat),
it operates polymorphically by invoking the appropriate speak() method for each object.

____________________________________________________________

10. Type Identifications -

In Python, you can identify the type of an object using several methods. Here are some common
techniques:
1. Using the type() Function: The type() function returns the type of an object. It takes a
single argument and returns the type object.
x = 5
print(type(x)) # Output: <class 'int'>
• Using the isinstance() Function: The isinstance() function checks if an object
is an instance of a specified class or any of its subclasses. It takes two arguments: the object
and the class (or tuple of classes) to check against.
x = 5
print(isinstance(x, int)) # Output: True

• Using Comparison Operators: You can also use comparison operators to check the type of
an object.
x = 5
print(type(x) == int) # Output: True

• Using the __class__ Attribute: Every object in Python has a __class__ attribute that
holds a reference to its class.
x = 5
print(x.__class__) # Output: <class 'int'>

• Using type with Inheritance: You can also use type to check if an object is an instance
of a class or any of its subclasses.
class A:
pass

class B(A):
pass

x = B()
print(type(x) is A) # Output: False
print(type(x) is B) # Output: True

Choose the method that best suits your needs based on the context and requirements of your code.
Each method has its advantages and use cases.

____________________________________________________________

11. Custom Exception Classes - Custom exception classes in Python allow you to
define your own exception types to handle specific error conditions in your code. By creating
custom exception classes, you can make your code more expressive, readable, and maintainable.
Here's how you can create custom exception classes in Python:
1. Subclass Exception: To create a custom exception class, you typically subclass the built-
in Exception class or one of its subclasses, such as ValueError, TypeError, etc.

2. Define Your Exception: Define your custom exception class by providing a name for the
class and optionally adding additional attributes or methods as needed.
3. Raise Your Custom Exception: In your code, raise an instance of your custom exception
class when a specific error condition occurs.
Here's a simple example of a custom exception class:
class CustomError(Exception):
def __init__(self, message="A custom error occurred"):
self.message = message
super().__init__(self.message)

# Example usage
def divide(x, y):
if y == 0:
raise CustomError("Cannot divide by zero")
return x / y

try:
result = divide(10, 0)
except CustomError as e:
print("Error:", e.message)

In this example:
• We define a custom exception class CustomError that inherits from the built-in
Exception class.
• The __init__() method initializes the exception object with an optional error message.
• Inside the divide() function, if the divisor y is zero, we raise an instance of
CustomError with a specific error message.
• In the try block, we call the divide() function and handle the raised exception by
printing the error message.
Custom exception classes are useful for organizing and handling errors in a structured way,
especially when you need to differentiate between different types of errors in your code. They allow
you to provide more context and information about the error condition, making it easier to debug
and troubleshoot issues.

____________________________________________________________

12. Iterators - Iterators in Python are objects that implement the iterator protocol, which
consists of two methods: __iter__() and __next__(). Iterators are used to iterate over a
sequence of elements, one element at a time, and they maintain internal state to keep track of the
current position within the sequence.
Here's a brief overview of iterators in Python:
1. __iter__() Method: This method returns the iterator object itself. It is called when the
iterator is initialized or reset for iteration.
2. __next__() Method: This method returns the next element in the sequence. It raises a
StopIteration exception when there are no more elements to return.

3. Iterable Objects: An object is iterable if it implements the __iter__() method, which


returns an iterator. Many built-in Python data types, such as lists, tuples, dictionaries, and
strings, are iterable.
4. Iterating with for Loops: In Python, for loops are designed to work with iterators. When
you iterate over an iterable object using a for loop, Python automatically calls the
__iter__() method to obtain an iterator and then repeatedly calls the __next__()
method to retrieve elements from the iterator until a StopIteration exception is raised.
5. Iterator Exhaustion: Once an iterator has been exhausted (i.e., all elements have been
retrieved), subsequent calls to its __next__() method will raise a StopIteration
exception.
Here's a simple example of creating and using an iterator in Python:
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0

def __iter__(self):
return self

def __next__(self):
if self.index >= len(self.data):
raise StopIteration
else:
value = self.data[self.index]
self.index += 1
return value

# Create an iterator object


my_iterator = MyIterator([1, 2, 3, 4, 5])

# Iterate over the iterator using a for loop


for item in my_iterator:
print(item) # Output: 1 2 3 4 5

In this example:
• MyIterator is a custom iterator class that iterates over a list of integers.
• The __iter__() method returns the iterator object itself.
• The __next__() method retrieves the next element from the list and updates the internal
index. If there are no more elements, it raises a StopIteration exception.
• The for loop iterates over the my_iterator object, repeatedly calling its __next__()
method to retrieve elements until the iterator is exhausted.

____________________________________________________________

13. Generators - Generators in Python are a convenient way to create iterators. They are
implemented using a special kind of function called a generator function, which uses the yield
keyword to yield values one at a time instead of returning them all at once. This allows you to
iterate over a potentially infinite sequence of values without consuming excessive memory.
Here's a summary of generators in Python:
1. Generator Function: A generator function is defined like a regular function, but it contains
one or more yield statements instead of a return statement. When called, a generator
function returns a generator object, which is an iterator.
2. yield Statement: The yield statement is used inside a generator function to yield a
value to the caller. When the generator function is called, execution is suspended at the
yield statement, and the yielded value is returned. The generator function retains its state,
allowing it to resume execution from where it left off when called again.
3. Iteration: Generators can be iterated over using a for loop, just like other iterable objects.
Each iteration calls the generator function's body until a yield statement is encountered, at
which point control is returned to the caller with the yielded value.
4. Lazy Evaluation: Generators produce values lazily, meaning they generate values on
demand as they are iterated over. This allows them to efficiently handle large or infinite
sequences without precomputing all values upfront.
5. Memory Efficiency: Because generators produce values on-the-fly and do not store the
entire sequence in memory, they are memory efficient, especially when dealing with large
data sets or infinite sequences.
Here's an example of a generator function that generates Fibonacci numbers:
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b

# Create a generator object


fib_gen = fibonacci()

# Generate and print the first 10 Fibonacci numbers


for _ in range(10):
print(next(fib_gen)) # Output: 0 1 1 2 3 5 8 13 21 34

In this example:
• The fibonacci() function is a generator function that yields Fibonacci numbers
indefinitely.
• We create a generator object fib_gen by calling the fibonacci() function.
• We use a for loop to iterate over the generator object and print the first 10 Fibonacci
numbers. Each call to next(fib_gen) advances the generator to the next yield statement,
producing the next Fibonacci number.

____________________________________________________________

14. Decorators - Decorators are a powerful feature in Python that allow you to modify or
extend the behavior of functions or methods without changing their source code. Decorators are
implemented using functions and provide a clean and concise way to add functionality to existing
code.
Here are the key points about decorators in Python:
1. Function Decorators: Decorators are implemented as regular Python functions that take
another function as an argument and return a new function. They are typically used with the
@decorator_name syntax, placed above the function definition.

2. Higher-Order Functions: Decorators are an example of higher-order functions, which are


functions that take other functions as arguments or return functions as results.
3. Decorator Syntax: To apply a decorator to a function, you prefix the function definition
with the decorator name prefixed by the @ symbol. This is called decorator syntax.
4. Common Use Cases: Decorators are commonly used for tasks such as logging,
authentication, caching, performance monitoring, and more. They allow you to separate
concerns and keep your code modular and maintainable.
5. Chaining Decorators: You can apply multiple decorators to a single function by stacking
them on top of each other, with each decorator applied in the order they appear.
6. Class Decorators: In addition to function decorators, Python also supports class decorators,
which operate on classes instead of functions. Class decorators are less common but can be
useful for certain tasks.
Here's a simple example of a decorator that logs the execution of a function:
def logger(func):
def wrapper(*args, **kwargs):
print(f"Calling function {func.__name__} with args {args} and kwargs
{kwargs}")
return func(*args, **kwargs)
return wrapper

@logger
def add(a, b):
return a + b

result = add(10, 20)


# Output: Calling function add with args (10, 20) and kwargs {}

In this example:
• The logger() function is a decorator that takes another function func as its argument.
• Inside logger(), a new function wrapper is defined, which adds logging functionality
around the original function func.
• The wrapper function calls the original function func with the provided arguments and
keyword arguments.
• The @logger decorator is applied to the add() function, which means that calls to
add() will be intercepted and logged by the logger() decorator.

____________________________________________________________
Chapter 3
I/O and Error Handling
1. Introduction -
In Python, input/output (I/O) operations and error handling are crucial aspects of programming.
Here's a brief overview of both:
Input/Output (I/O):
1. Printing Output: The print() function is used to display output on the console. You can
print strings, variables, and expressions.
print("Hello, world!")

• Reading Input: The input() function is used to accept input from the user. It returns the
user's input as a string.
name = input("Enter your name: ")

• File Handling: Python provides built-in functions and modules for file I/O operations. The
open() function is used to open a file. Use modes like 'r' for reading, 'w' for writing,
and 'a' for appending.
# Reading from a file
with open("filename.txt", "r") as file:
data = file.read()

# Writing to a file
with open("output.txt", "w") as file:
file.write("Hello, world!")

Error Handling:
Python uses the try, except, finally, and else blocks for error handling. This allows you to
handle exceptions gracefully.
1. try-except block: Used to catch exceptions. Code within the try block is executed, and if
any exception occurs, it is caught by the except block.
try:
# Code that may raise an exception
result = 10 / 0
except ZeroDivisionError:
print("Error: Division by zero!")

• finally block: Optional block executed regardless of whether an exception occurred or not.
It's typically used for cleanup actions.
try:
# Code that may raise an exception
result = 10 / 0
except ZeroDivisionError:
print("Error: Division by zero!")
finally:
print("Execution complete.")

• else block: Executed if the code in the try block doesn’t raise any exceptions.
try:
# Code that may raise an exception
result = 10 / 2
except ZeroDivisionError:
print("Error: Division by zero!")
else:
print("Result:", result)

Error handling allows your program to handle unexpected situations without crashing and provides
mechanisms for graceful recovery or appropriate error messages.

____________________________________________________________

2. Data Streams - In Python, data streams are a way of handling continuous flows of data,
whether from input sources like files, network sockets, or output destinations like files, network
connections, or standard output. Python provides several modules and functions to work with data
streams efficiently. Here's an overview:
1. File Streams:
Python's file I/O functionality allows reading from and writing to files, which are a common form
of data streams.
• Reading from Files:
with open("data.txt", "r") as file:
for line in file:
print(line)

• Writing to Files:
with open("output.txt", "w") as file:
file.write("Hello, world!")

2. Standard Streams:
Python also provides access to the standard input, output, and error streams through sys.stdin,
sys.stdout, and sys.stderr, respectively, in the sys module.

• Standard Input:
import sys

for line in sys.stdin:


print(line)

• Standard Output:
import sys

sys.stdout.write("Hello, world!\n")
3. Network Streams:
Python's socket module enables communication over networks, allowing you to read from and
write to network connections.
• Socket for TCP Client:

import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("example.com", 80))

data = client_socket.recv(1024)
print("Received:", data.decode())

client_socket.close()

• Socket for TCP Server:


import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


server_socket.bind(("127.0.0.1", 8080))
server_socket.listen(1)

while True:
client_socket, address = server_socket.accept()
data = client_socket.recv(1024)
print("Received:", data.decode())

client_socket.close()

These are just a few examples of how Python handles data streams. Depending on your
requirements, you might also explore libraries like io for more advanced stream processing or
third-party libraries for specific needs, such as requests for HTTP requests or pandas for data
manipulation.

____________________________________________________________

3. Creating your own Data Stream -Creating your own data stream involves defining
a class that implements the stream interface. Here's a simple example of how you can create a
custom data stream class in Python:

class DataStream:
def __init__(self, data):
self.data = data
self.index = 0

def read(self):
if self.index >= len(self.data):
return None
else:
value = self.data[self.index]
self.index += 1
return value

def write(self, value):


self.data.append(value)
# Example usage:
stream = DataStream([1, 2, 3, 4, 5])

# Reading from the stream


print("Reading from the stream:")
while True:
value = stream.read()
if value is None:
break
print(value)

# Writing to the stream


stream.write(6)
print("Data written to the stream:", stream.data)

In this example:
• The DataStream class has an internal data list that stores the data.
• The read method reads data from the stream sequentially.
• The write method appends data to the stream.

You can customize this class according to your specific needs, such as adding error handling,
buffering, or implementing additional methods for seeking, flushing, or closing the stream.
Creating your own data stream allows you to abstract away the complexity of handling data from
various sources or to simulate streams for testing purposes. Depending on your requirements, you
might extend this example to support more advanced features or integrate it with other parts of your
application.

____________________________________________________________

4. Access Modes - In Python, access modes are used when opening files to specify the
operations that can be performed on the file. These modes determine whether the file is opened for
reading, writing, or both, as well as whether the file should be created if it doesn't exist or truncated
if it does. Here are the commonly used access modes:
1. Read Mode ('r'):
• Opens the file for reading.
• The file pointer is placed at the beginning of the file.
• If the file does not exist, it raises a FileNotFoundError.
with open("example.txt", "r") as file:
data = file.read()

Write Mode ('w'):


• Opens the file for writing.
• If the file exists, its contents are overwritten.
• If the file does not exist, it creates a new file.
• The file pointer is placed at the beginning of the file.
with open("example.txt", "w") as file:
file.write("Hello, world!")
Append Mode ('a'):
• Opens the file for writing.
• If the file exists, new data is appended to the end of the file.
• If the file does not exist, it creates a new file.
• The file pointer is placed at the end of the file.
with open("example.txt", "a") as file:
file.write("New data appended!")

Read and Write Mode ('r+'):


• Opens the file for both reading and writing.
• The file pointer is placed at the beginning of the file.
• If the file does not exist, it raises a FileNotFoundError.
with open("example.txt", "r+") as file:
data = file.read()
file.write("Additional data")

Write and Read Mode ('w+'):


• Opens the file for both reading and writing.
• If the file exists, its contents are overwritten.
• If the file does not exist, it creates a new file.
• The file pointer is placed at the beginning of the file.
with open("example.txt", "w+") as file:
file.write("Hello, world!")
file.seek(0)
data = file.read()

Append and Read Mode ('a+'):


• Opens the file for both reading and writing.
• If the file exists, new data is appended to the end of the file.
• If the file does not exist, it creates a new file.
• The file pointer is placed at the end of the file.
with open("example.txt", "a+") as file:
file.write("New data appended!")
file.seek(0)
data = file.read()

These are the basic access modes in Python for file I/O operations. Depending on your
requirements, you can choose the appropriate mode to perform read, write, or read-write operations
on files.

____________________________________________________________

5. Writing Data To a File -Writing data to a file in Python involves opening a file in write
mode and then using methods to write data to it. Here's a basic example:
python

# Open a file in write mode ('w')


with open("output.txt", "w") as file:
# Write data to the file
file.write("Hello, world!\n")
file.write("This is a new line.\n")

In this example:
• The open() function is used to open a file named "output.txt" in write mode ("w"). If the
file doesn't exist, it will be created. If it does exist, its contents will be overwritten.
• The with statement ensures that the file is properly closed after writing, even if an
exception occurs during the writing process.
• The write() method is used to write data to the file. You can pass a string to this method
to write it to the file.
After executing this code, a file named "output.txt" will be created (or overwritten if it already
exists) in the current directory with the following contents:
Hello, world!
This is a new line.

You can write any data to the file using the write() method, including strings, numbers, or even
the contents of other files. Just make sure to convert non-string data types to strings before writing
them to the file.

____________________________________________________________

6. Reding Data From a File - Reading data from a file in Python involves opening the
file in read mode and then using methods to read data from it. Here's a basic example:
# Open a file in read mode ('r')
with open("input.txt", "r") as file:
# Read data from the file
data = file.read()
print(data)

In this example:
• The open() function is used to open a file named "input.txt" in read mode ("r").
• The with statement ensures that the file is properly closed after reading, even if an
exception occurs during the reading process.
• The read() method is used to read the entire contents of the file as a single string and store
it in the variable data.

After executing this code, the contents of the file "input.txt" will be printed to the console.
You can also read the file line by line using a loop:
# Open a file in read mode ('r')
with open("input.txt", "r") as file:
# Read data line by line
for line in file:
print(line.strip()) # strip() removes leading and trailing whitespace
and newline characters
This will print each line of the file "input.txt" to the console, removing leading and trailing
whitespace and newline characters using the strip() method.

You can also use methods like readline() to read a single line at a time, or readlines() to
read all lines into a list. Choose the method that best fits your specific use case.

____________________________________________________________

7. Additional File Method - Certainly! Alongside read(), readline(), and


readlines(), Python's file objects offer additional methods for more granular control and
flexibility when working with files:
1. write(): Writes a string to the file.
with open("output.txt", "w") as file:
file.write("Hello, world!\n")

• writelines(): Writes a list of strings to the file.


lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open("output.txt", "w") as file:
file.writelines(lines)

• seek(offset, whence): Moves the file pointer to a specified position.


with open("input.txt", "r") as file:
file.seek(5) # Move to the 6th byte in the file
data = file.read()

• tell(): Returns the current position of the file pointer.


with open("input.txt", "r") as file:
print("Current position:", file.tell())

• flush(): Flushes the internal buffer, ensuring that all buffered data is written to the file.
with open("output.txt", "w") as file:
file.write("Hello, world!")
file.flush()

• truncate(size): Truncates the file to a specified size.


with open("output.txt", "r+") as file:
file.truncate(10) # Truncate the file to 10 bytes

• close(): Closes the file. Though not strictly necessary when using the with statement
(as it automatically closes the file), it's useful when working with file objects outside of a
with context.
file = open("input.txt", "r")
data = file.read()
file.close()

These methods provide you with powerful capabilities to manipulate files in various ways, from
writing and reading data to controlling the file pointer and managing buffers.

____________________________________________________________
8. Handling IO Exceptions - Handling I/O exceptions is essential for robust file
handling in Python. File operations can fail due to various reasons, such as a file not existing,
insufficient permissions, or disk space issues. Python provides mechanisms to catch and handle
these exceptions gracefully using try-except blocks. Here's how you can handle I/O exceptions
effectively:
try:
# Open the file for reading
with open("input.txt", "r") as file:
# Read data from the file
data = file.read()
print(data)
except FileNotFoundError:
print("File not found!")
except PermissionError:
print("Permission denied!")
except IOError as e:
print("I/O error:", e)
except Exception as e:
print("An unexpected error occurred:", e)

In this example:
• We attempt to open a file named "input.txt" for reading within a try block.
• Inside the try block, we read data from the file.
• If any exceptions occur during file operations, Python checks each except block to see if it
matches the type of exception raised. If a match is found, the corresponding block is
executed.
• The FileNotFoundError exception is raised when the specified file does not exist,
while PermissionError is raised when there are insufficient permissions to perform the
file operation.
• The IOError is a generic exception for I/O-related errors. We can catch it to handle any
other I/O errors not explicitly handled by more specific exception types.
• The Exception block catches any other unexpected exceptions that might occur.
• In each except block, we print an appropriate error message or handle the exception in a
way that's suitable for our application.
By handling I/O exceptions, you can make your code more robust and resilient to unexpected
situations when working with files.

____________________________________________________________

9. Errors - Errors in programming, including in Python, can broadly be categorized into two
main types: syntax errors and exceptions.
1. Syntax Errors: Syntax errors, also known as parsing errors, occur when the code violates
the syntax rules of the programming language. These errors are detected by the Python
interpreter during the parsing phase before the code is executed. Common examples include
missing colons, mismatched parentheses, or misspelled keywords.
• # Syntax Error: Missing colon
if x == 5
print("x is equal to 5")
When you run code with a syntax error, Python will raise a SyntaxError and provide
information about the error, including the location of the syntax violation.
• Exceptions: Exceptions, on the other hand, occur during the execution of a program when
something unexpected happens. These can include errors like division by zero, attempting to
access an index that doesn't exist in a list, or attempting to open a file that doesn't exist.
Exceptions disrupt the normal flow of the program unless they are handled appropriately.
# ZeroDivisionError: Division by zero
result = 10 / 0

To handle exceptions, you can use try, except, finally, and else blocks to gracefully
recover from errors or provide appropriate error messages to users.
2. try:
result = 10 / 0
except ZeroDivisionError:
print("Error: Division by zero!")

In this example, if a ZeroDivisionError occurs during the division operation, the code
inside the except block is executed, preventing the program from crashing.

Understanding and handling errors effectively is essential for writing robust and reliable code.
Python's error handling mechanisms provide ways to identify, anticipate, and recover from errors,
ensuring smoother execution of programs.

____________________________________________________________

10. Run Time Errors - Runtime errors, also known as exceptions, occur during the
execution of a program. Unlike syntax errors, which are caught by the Python interpreter during the
parsing phase, runtime errors happen while the program is running. These errors can occur due to
various reasons, such as invalid input, division by zero, attempting to access an index out of range,
or using a variable that hasn't been initialized.
Here are some common types of runtime errors in Python:
1. ZeroDivisionError: Occurs when dividing a number by zero.
result = 10 / 0

• TypeError: Occurs when an operation is performed on an object of inappropriate type.


result = "Hello" + 5

• IndexError: Occurs when trying to access an index that is out of range for a sequence (e.g.,
list, tuple).
my_list = [1, 2, 3]
print(my_list[3])

• KeyError: Occurs when trying to access a dictionary key that does not exist.
my_dict = {"a": 1, "b": 2}
print(my_dict["c"])
• ValueError: Occurs when a built-in operation or function receives an argument with the
right type but an inappropriate value.
num = int("abc")

• FileNotFoundError: Occurs when trying to open a file that does not exist.
6. with open("nonexistent_file.txt", "r") as file:
data = file.read()

To handle runtime errors, you can use try, except, finally, and else blocks to gracefully
recover from errors or provide appropriate error messages to users. Proper error handling helps
ensure that your program can handle unexpected situations and continues to execute smoothly.

____________________________________________________________

11. The Exception Model - The exception model in Python is a mechanism for handling
runtime errors (exceptions) that occur during the execution of a program. It provides a way to detect
and respond to exceptional conditions that may arise during program execution. Here's an overview
of the key components of the exception model in Python:
1. Exceptions: Exceptions are objects representing errors or exceptional conditions that occur
during program execution. Python provides a variety of built-in exception classes for
common types of errors, such as ZeroDivisionError, TypeError, ValueError,
FileNotFoundError, and more. Additionally, you can define your own custom
exception classes by subclassing Exception or one of its subclasses.

2. try-except Block: The try statement is used to wrap the code that may raise an exception.
It allows you to catch and handle exceptions gracefully. The except block specifies the
type of exception to catch and provides the code to handle the exception.
• try:
# Code that may raise an exception
result = 10 / 0
except ZeroDivisionError:
# Code to handle the ZeroDivisionError exception
print("Error: Division by zero!")

• Multiple Except Blocks: You can have multiple except blocks to handle different types
of exceptions. Python will execute the code in the first matching except block and ignore
subsequent blocks.
• try:
# Code that may raise an exception
result = 10 / 0
except ZeroDivisionError:
# Code to handle the ZeroDivisionError exception
print("Error: Division by zero!")
except ValueError:
# Code to handle the ValueError exception
print("Error: Invalid input!")

• else Block: The else block is executed if no exceptions occur within the try block. It is
typically used to execute code that should run only if no exceptions were raised.
• try:
# Code that may raise an exception
result = 10 / 2
except ZeroDivisionError:
# Code to handle the ZeroDivisionError exception
print("Error: Division by zero!")
else:
# Code to execute if no exceptions occurred
print("Result:", result)

• finally Block: The finally block is always executed regardless of whether an exception
occurred or not. It is commonly used for cleanup actions, such as closing files or releasing
resources.
• try:
# Code that may raise an exception
file = open("example.txt", "r")
data = file.read()
except FileNotFoundError:
# Code to handle the FileNotFoundError exception
print("Error: File not found!")
finally:
# Code to execute for cleanup
if file:
file.close()

• Raising Exceptions: You can explicitly raise exceptions using the raise statement. This
allows you to signal that an error condition has occurred in your code.
if x < 0:
raise ValueError("x must be non-negative")

1. Exception Hierarchy: Python's built-in exceptions are organized into a hierarchy, with the
base class being BaseException. This hierarchy allows you to catch more general
exceptions or specific ones, depending on your needs.
Overall, the exception model in Python provides a powerful and flexible way to handle errors and
exceptional conditions in your code, improving its robustness and reliability.

____________________________________________________________

12. Exception Hierarchy - In Python, the exception hierarchy is organized in a tree-like


structure, with the base class being BaseException. Here's a brief overview of the main
categories in the Python exception hierarchy:
1. BaseException:
• This is the base class for all built-in exceptions. It's not meant to be directly inherited
by user-defined exceptions.
• Examples of exceptions directly inheriting from BaseException include
SystemExit, KeyboardInterrupt, and GeneratorExit.
2. Exception:
• This is the base class for all built-in, non-system-exiting exceptions.
• Most built-in exceptions inherit directly or indirectly from Exception.
• Examples include ArithmeticError, LookupError, and
EnvironmentError (deprecated since Python 3.3, split into more specific
exceptions).
3. ArithmeticError:
• This class serves as the base class for exceptions that occur during arithmetic
operations.
• Subclasses include ZeroDivisionError, OverflowError, and
FloatingPointError.
4. LookupError:
• This class serves as the base class for exceptions that occur when a key or index is
not found.
• Subclasses include IndexError and KeyError.
5. IOError (deprecated since Python 3.3):
• This class served as the base class for I/O-related exceptions.
• In Python 3, OSError is used instead, which itself is a subclass of Exception.
6. OSError:
• This class serves as the base class for exceptions that occur during operating system-
related operations.
• Subclasses include FileNotFoundError, PermissionError, and
TimeoutError.
7. StopIteration:
• This exception is raised by iterator objects when there are no more elements to be
returned.
• It's commonly used in iteration protocols.
8. EnvironmentError (deprecated since Python 3.3):
• This class served as the base class for exceptions related to the environment.
• In Python 3, environment-related exceptions are more specifically categorized under
other exception classes, such as FileNotFoundError and
PermissionError.

These are just some of the main categories in the Python exception hierarchy. Each exception class
typically provides information about a specific type of error, allowing for more precise error
handling in your code. Understanding the exception hierarchy can help you choose the appropriate
exception to catch and handle in different situations.

____________________________________________________________

13. Handling Multiple Exceptions - Handling multiple exceptions in Python allows


you to provide specific handling for different types of errors that may occur within your code. You
can use multiple except blocks to catch and handle each type of exception separately. Here's an
example:
python

try:
# Code that may raise exceptions
result = 10 / 0
except ZeroDivisionError:
# Handle division by zero error
print("Error: Division by zero!")
except TypeError:
# Handle type error
print("Error: Invalid operation!")
except Exception as e:
# Handle other exceptions
print("An unexpected error occurred:", e)

In this example:
• We have a try block containing the code that may raise exceptions.
• We use multiple except blocks, each targeting a specific type of exception
(ZeroDivisionError, TypeError, and a generic Exception).
• If a ZeroDivisionError occurs (division by zero), the code inside the corresponding
except block is executed.
• If a TypeError occurs (invalid operation), the code inside its except block is executed.
• The generic except Exception as e block catches any other exceptions not
explicitly handled by the previous except blocks. It prints an error message along with the
exception details.
You can also use a single except block to catch multiple types of exceptions by specifying them
as a tuple:
try:
# Code that may raise exceptions
result = int("abc")
except (ValueError, TypeError):
# Handle value and type errors
print("Error: Invalid input!")

This approach is useful when you want to handle different types of exceptions in the same way.
When handling multiple exceptions, it's essential to consider the order of the except blocks.
Python checks each except block in order, and the first matching block is executed. Therefore, if
you have a generic except block at the end, make sure to place more specific exception handlers
before it to avoid catching exceptions unintentionally.

____________________________________________________________

14. Working with Directories - Working with directories in Python is commonly done
using the os module, which provides various functions for interacting with the operating system.
Here's how you can perform common directory-related operations:
1. Creating a Directory:
You can create a new directory using the os.mkdir() function.
import os

# Create a new directory


os.mkdir("new_directory")
2. Checking if a Directory Exists:
You can check if a directory exists using the os.path.exists() function.
import os

# Check if a directory exists


if os.path.exists("new_directory"):
print("Directory exists")
else:
print("Directory does not exist")

3. Listing Files and Directories:


You can list the files and directories within a directory using the os.listdir() function.
import os

# List files and directories in a directory


contents = os.listdir("new_directory")
print("Contents:", contents)

4. Changing the Current Working Directory:


You can change the current working directory using the os.chdir() function.]
import os

# Change the current working directory


os.chdir("new_directory")

5. Removing a Directory:
You can remove a directory using the os.rmdir() function.
import os

# Remove a directory
os.rmdir("new_directory")

6. Checking if a Path is a Directory:


You can check if a path points to a directory using the os.path.isdir() function.
import os

# Check if a path is a directory


if os.path.isdir("new_directory"):
print("Path is a directory")
else:
print("Path is not a directory")

These are some of the basic operations you can perform when working with directories in Python.
The os module provides many more functions for directory manipulation and path handling,
allowing you to interact with the file system in a platform-independent way.

____________________________________________________________
Chapter 4
An Introduction to relational database

1. SQL statements for data manipulation - SQL (Structured Query Language)


provides various statements for data manipulation, allowing you to interact with a database to insert,
update, delete, or query data. Here are some common SQL statements for data manipulation:
1. SELECT: Retrieves data from one or more tables based on specified criteria.
SELECT column1, column2 FROM table_name WHERE condition;

2. INSERT INTO: Inserts new records into a table.


INSERT INTO table_name (column1, column2) VALUES (value1, value2);

3. UPDATE: Modifies existing records in a table.


UPDATE table_name SET column1 = value1, column2 = value2 WHERE condition;

4. DELETE: Removes records from a table.


DELETE FROM table_name WHERE condition;

5. UPSERT (or MERGE): Inserts a new record if it does not exist or updates the existing
record if it does.
-- PostgreSQL
INSERT INTO table_name (column1, column2) VALUES (value1, value2)
ON CONFLICT (column_unique_constraint) DO UPDATE SET column1 = value1, column2 =
value2;

-- MySQL
INSERT INTO table_name (column1, column2) VALUES (value1, value2)
ON DUPLICATE KEY UPDATE column1 = value1, column2 = value2;

6. TRUNCATE: Removes all records from a table.


TRUNCATE TABLE table_name;

7. ALTER TABLE: Modifies the structure of a table (e.g., adding, modifying, or dropping
columns).
ALTER TABLE table_name ADD column_name datatype;
ALTER TABLE table_name MODIFY column_name datatype;
ALTER TABLE table_name DROP COLUMN column_name;

8. CREATE TABLE: Creates a new table with specified columns and constraints.
CREATE TABLE table_name (
column1 datatype,
column2 datatype,
...
);

9. DROP TABLE: Deletes an existing table.


DROP TABLE table_name;

These are some of the fundamental SQL statements for data manipulation. Depending on the
database management system (DBMS) you are using (e.g., MySQL, PostgreSQL, SQL Server,
Oracle), the syntax and features may vary slightly.

____________________________________________________________

2. Using SQLite Manager to work with a database - Great! SQLite is a


lightweight, file-based relational database management system that is widely used for development
and testing purposes. SQLite Manager is a graphical user interface (GUI) tool that allows you to
manage SQLite databases easily. It provides a visual way to create, edit, and manipulate SQLite
databases. Here's a brief overview of how you can use SQLite Manager to work with a database:
1. Install SQLite Manager: You can install SQLite Manager as a browser extension in Firefox
or as a standalone application. If you're using Firefox, you can find and install SQLite
Manager from the Firefox Add-ons store. If you prefer the standalone application, you can
download it from the SQLite Manager website and install it on your system.
2. Open SQLite Manager: Once installed, open SQLite Manager from the Firefox Add-ons
menu or launch the standalone application.
3. Connect to a Database: In SQLite Manager, you can connect to an existing SQLite
database file (.sqlite or .db) or create a new one. Click on the "Database" menu and select
"Connect Database" to open a file dialog where you can browse for your SQLite database
file. If you want to create a new database, select "New Database" and specify the file name
and location.
4. View Database Structure: After connecting to a database, you can view its structure in the
"Database Structure" tab. This tab shows all the tables in the database along with their
columns and indexes.
5. Execute SQL Queries: SQLite Manager allows you to execute SQL queries directly on the
database. Switch to the "Execute SQL" tab, enter your SQL query in the editor, and click the
"Run SQL" button to execute it. You can use this feature to perform various data
manipulation tasks such as selecting, inserting, updating, or deleting records.
6. Import and Export Data: SQLite Manager enables you to import and export data to and
from the database. You can import data from CSV files or export query results to CSV,
JSON, XML, or SQL format.
7. Manage Indexes and Triggers: In SQLite Manager, you can create, edit, or delete indexes
and triggers for your database tables. These features help you optimize query performance
and enforce data integrity constraints.
8. Backup and Restore: SQLite Manager allows you to easily backup and restore your SQLite
databases. You can create backups of your database files for safekeeping or restore them
from backups in case of data loss or corruption.
9. Manage Preferences: You can customize SQLite Manager's behavior and appearance by
adjusting various preferences such as font size, theme, and default settings for new
databases.
10.Close Database Connection: After you've finished working with a database, you can close
the connection by selecting "Disconnect Database" from the "Database" menu. This closes
the database file and frees up system resources.
These are some of the basic tasks you can perform with SQLite Manager to work with SQLite
databases. As you become more familiar with the tool, you'll discover additional features and
functionalities that can further enhance your database management experience.

____________________________________________________________

3. Using Python to work with a database - Working with databases in Python is


commonly done using database libraries such as SQLite, MySQL, PostgreSQL, or SQLAlchemy.
Here's a basic overview of how you can use Python to interact with a database, using SQLite as an
example:
1. Install the Database Library: Depending on the database you're using, you'll need to install
the corresponding Python library. For SQLite, you don't need to install anything extra
because SQLite comes pre-installed with Python. For other databases like MySQL or
PostgreSQL, you'll need to install the respective library (e.g., mysql-connector-
python for MySQL).

2. Connect to the Database: Use the library's functions or methods to connect to the database.
For SQLite, you can use the sqlite3 module from the Python standard library to connect
to an SQLite database file.
python

import sqlite3

# Connect to an SQLite database (or create one if it doesn't exist)


conn = sqlite3.connect('example.db')

# Create a cursor object to execute SQL queries


cursor = conn.cursor()

3. Execute SQL Queries: Use the cursor object to execute SQL queries on the database. You
can execute any SQL statement supported by the database, such as SELECT, INSERT,
UPDATE, DELETE, CREATE TABLE, etc.
# Execute SQL queries
cursor.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name
TEXT, age INTEGER)')
cursor.execute('INSERT INTO users (name, age) VALUES (?, ?)', ('John', 30))
conn.commit() # Commit the transaction

4. Fetch Data: If your SQL query returns data (e.g., SELECT queries), you can fetch the
results using methods like fetchone(), fetchall(), or fetchmany().
# Fetch data
cursor.execute('SELECT * FROM users WHERE age > ?', (25,))
rows = cursor.fetchall()
for row in rows:
print(row)

5. Close the Connection: Once you're done working with the database, don't forget to close
the connection to release resources.
# Close the connection
conn.close()

This is just a basic example of how you can work with a database in Python. Depending on your
specific use case and the complexity of your application, you may need to handle transactions,
handle errors, use ORM (Object-Relational Mapping) libraries like SQLAlchemy, and more.

____________________________________________________________

4. Creating a GUI that handles an event - Creating a GUI (Graphical User


Interface) that handles an event in Python is commonly done using libraries such as Tkinter, PyQt,
or Kivy. Here's an example using Tkinter, which is included with Python by default:
import tkinter as tk

def handle_event():
# Function to handle the button click event
print("Button clicked!")

# Create the main application window


root = tk.Tk()
root.title("Event Handling Example")

# Create a button widget


button = tk.Button(root, text="Click Me", command=handle_event)
button.pack()

# Run the Tkinter event loop


root.mainloop()

In this example:
• We import the tkinter module and define a function handle_event() to handle the
event when the button is clicked.
• We create the main application window using tk.Tk() and set its title.
• We create a button widget using tk.Button() with the text "Click Me" and specify the
command parameter to call the handle_event() function when the button is clicked.
• We use the pack() method to add the button to the window.
• Finally, we start the Tkinter event loop using root.mainloop(), which waits for events
(such as button clicks) and handles them accordingly.
When you run this code, a window will appear with a button labeled "Click Me". When you click
the button, the message "Button clicked!" will be printed in the console or terminal.
This is a basic example, and you can expand upon it to create more complex GUI applications with
multiple widgets and event handlers.
____________________________________________________________

6. working with components - Working with components in a graphical user interface


(GUI) involves creating, configuring, and interacting with various widgets or elements that make up
the interface. Let's explore how you can work with components in a Python GUI using Tkinter as an
example:

import tkinter as tk

def handle_button_click():
# Function to handle button click event
label.config(text="Button Clicked!")

# Create the main application window


root = tk.Tk()
root.title("GUI Example")

# Create and configure components


label = tk.Label(root, text="Hello, world!")
button = tk.Button(root, text="Click Me", command=handle_button_click)

# Add components to the window


label.pack()
button.pack()

# Run the Tkinter event loop


root.mainloop()

In this example:
• We import the tkinter module as tk.
• We define a function handle_button_click() to handle the event when the button is
clicked. In this case, it updates the text of the label.
• We create the main application window using tk.Tk() and set its title.
• We create components such as a label (tk.Label) and a button (tk.Button), and
configure them as needed.
• We add the components to the window using the pack() method, which organizes them in
a vertical layout.
• Finally, we start the Tkinter event loop using root.mainloop(), which waits for events
(such as button clicks) and handles them accordingly.
You can work with various other components such as text entry fields, check buttons, radio buttons,
list boxes, scroll bars, and more, depending on your application's requirements. Additionally, you
can customize the appearance and behavior of these components by configuring their properties and
attaching event handlers as needed.

____________________________________________________________
Chapter 5
Implement Machine Learning Algorithm
1. Usage of Numpy for numerical Data - NumPy is a powerful Python library for
numerical computing that provides support for large, multi-dimensional arrays and matrices, along
with a collection of mathematical functions to operate on these arrays efficiently. Here's a brief
overview of how you can use NumPy for numerical data manipulation:
1. Import NumPy: Begin by importing the NumPy library.
import numpy as np

2. Creating NumPy Arrays: You can create NumPy arrays using lists or tuples.
# 1D array
arr1 = np.array([1, 2, 3, 4, 5])

# 2D array
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

3. Array Attributes: NumPy arrays have various attributes such as shape, size, and data type.
print(arr1.shape) # (5,)
print(arr2.shape) # (3, 3)
print(arr2.size) # 9
print(arr2.dtype) # int64

4. Array Operations: NumPy provides a wide range of mathematical operations for arrays.
# Element-wise addition
result = arr1 + arr1

# Element-wise multiplication
result = arr1 * arr1

# Matrix multiplication
result = np.dot(arr2, arr2)

5. Indexing and Slicing: You can access elements of a NumPy array using indexing and
slicing.
# Accessing elements
print(arr1[0]) # 1
print(arr2[0, 1]) # 2

# Slicing
print(arr1[1:4]) # [2, 3, 4]
print(arr2[:, 1:]) # [[2, 3], [5, 6], [8, 9]]

6. Array Manipulation: NumPy provides functions for array manipulation, such as reshaping,
stacking, and splitting.
# Reshaping
arr3 = arr1.reshape((5, 1))

# Stacking
result = np.hstack((arr1, arr1))
result = np.vstack((arr2, arr2))
# Splitting
arr4, arr5 = np.split(arr2, [2])

7. Mathematical Functions: NumPy includes a wide range of mathematical functions for


arrays.
# Trigonometric functions
result = np.sin(arr1)

# Exponential and logarithmic functions


result = np.exp(arr1)
result = np.log(arr1)

# Statistical functions
result = np.mean(arr1)
result = np.std(arr1)

These are just a few examples of what you can do with NumPy for numerical data manipulation.
NumPy's extensive functionality and performance make it an essential tool for scientific computing
and data analysis in Python.

____________________________________________________________

2. Usage of Pandas for Data Analysis - Pandas is a powerful Python library for data
analysis that provides data structures and functions designed to make working with structured data
easy and intuitive. Here's an overview of how you can use Pandas for data analysis:
1. Import Pandas: Begin by importing the Pandas library.
import pandas as pd

2. Loading Data: Pandas provides functions to read data from various file formats such as
CSV, Excel, SQL databases, and more.
# Read data from a CSV file
df = pd.read_csv('data.csv')

# Read data from an Excel file


df = pd.read_excel('data.xlsx')

# Read data from a SQL database


# (requires additional libraries such as SQLAlchemy)

3. Exploring Data: Pandas provides functions to explore and understand the structure of the
data.
# Display the first few rows of the DataFrame
print(df.head())

# Display summary statistics of the DataFrame


print(df.describe())

# Display information about the DataFrame


print(df.info())

4. Indexing and Selecting Data: Pandas allows you to select subsets of data using indexing
and slicing.
# Select a single column
column = df['column_name']

# Select multiple columns


columns = df[['column1', 'column2']]

# Select rows based on conditions


subset = df[df['column'] > 10]

5. Data Cleaning and Preparation: Pandas provides functions for data cleaning and
preparation, such as handling missing values, removing duplicates, and transforming data.
# Handle missing values
df.dropna() # Drop rows with missing values
df.fillna(value) # Fill missing values with a specific value

# Remove duplicates
df.drop_duplicates()

# Data transformation
df['new_column'] = df['column'].apply(lambda x: x * 2)

6. Data Aggregation and Grouping: Pandas allows you to aggregate and group data for
analysis.
# Group data by a column and compute aggregate statistics
grouped = df.groupby('column').agg({'column2': 'mean'})

# Pivot table
pivot_table = df.pivot_table(index='column1', columns='column2', values='value',
aggfunc='mean')

7. Data Visualization: Pandas integrates with Matplotlib and other visualization libraries to
create plots and charts.
# Plot data
df.plot(x='column1', y='column2', kind='scatter')

# Histogram
df['column'].plot(kind='hist')

These are just a few examples of what you can do with Pandas for data analysis. Pandas' rich
functionality and ease of use make it a popular choice for data manipulation and analysis in Python.

____________________________________________________________

3. Matplotlib for Python plotting - Matplotlib is a comprehensive library for creating


static, animated, and interactive visualizations in Python. It provides a wide variety of plotting
functions and customization options to create publication-quality plots. Here's an overview of how
you can use Matplotlib for plotting:
1. Import Matplotlib: Begin by importing the Matplotlib library.
import matplotlib.pyplot as plt

2. Creating Basic Plots: Matplotlib provides functions to create various types of plots, such as
line plots, scatter plots, bar plots, histograms, and more.
# Line plot
plt.plot(x_values, y_values)
# Scatter plot
plt.scatter(x_values, y_values)

# Bar plot
plt.bar(x_values, y_values)

# Histogram
plt.hist(data, bins=10)

3. Customizing Plots: Matplotlib allows you to customize the appearance of plots by


modifying colors, markers, line styles, labels, titles, and more.
# Adding labels and title
plt.xlabel('X-axis label')
plt.ylabel('Y-axis label')
plt.title('Plot Title')

# Customizing line style and marker


plt.plot(x_values, y_values, linestyle='--', marker='o', color='red')

# Adding legend
plt.legend(['Line 1', 'Line 2'])

# Changing plot size


plt.figure(figsize=(8, 6))

4. Multiple Subplots: Matplotlib supports creating multiple subplots within a single figure.
# Create a figure with multiple subplots
plt.subplot(2, 2, 1) # 2 rows, 2 columns, subplot 1
plt.plot(x1, y1)

plt.subplot(2, 2, 2) # subplot 2
plt.scatter(x2, y2)

plt.subplot(2, 2, 3) # subplot 3
plt.bar(x3, y3)

plt.subplot(2, 2, 4) # subplot 4
plt.hist(data)

5. Saving Plots: You can save plots as image files (e.g., PNG, PDF) using Matplotlib.
plt.savefig('plot.png')

6. Displaying Plots: Matplotlib provides functions to display plots interactively or inline in


Jupyter notebooks.
plt.show() # Display plot interactively

# For Jupyter notebooks


%matplotlib inline

These are just a few examples of what you can do with Matplotlib for plotting in Python.
Matplotlib's extensive functionality and flexibility make it a versatile tool for creating a wide range
of visualizations.

____________________________________________________________
4. Seaborn for Statistical plots - Seaborn is a Python visualization library based on
Matplotlib that provides a high-level interface for creating attractive and informative statistical
plots. It simplifies the process of creating complex visualizations by providing easy-to-use functions
with sensible defaults. Here's an overview of how you can use Seaborn for statistical plots:
1. Import Seaborn: Begin by importing the Seaborn library.
import seaborn as sns

2. Loading Data: Seaborn works well with Pandas DataFrames, so you can load your data into
a DataFrame and pass it to Seaborn functions.
import pandas as pd

# Load data into a DataFrame


df = pd.read_csv('data.csv')

3. Creating Statistical Plots: Seaborn provides functions to create various types of statistical
plots with minimal code.
# Scatter plot with linear regression line
sns.regplot(x='x_column', y='y_column', data=df)

# Pair plot for exploring relationships between multiple variables


sns.pairplot(df)

# Box plot to show distribution of a continuous variable by categories


sns.boxplot(x='category_column', y='numeric_column', data=df)

4. Customizing Plots: Seaborn allows you to customize the appearance of plots using various
parameters.
# Changing color palette
sns.scatterplot(x='x_column', y='y_column', data=df, palette='muted')

# Adding titles and labels


plt.title('Title')
plt.xlabel('X-label')
plt.ylabel('Y-label')

5. Faceting: Seaborn supports faceting, which allows you to create multiple plots based on
subsets of the data.
# Facet grid for visualizing relationships by categories
g = sns.FacetGrid(df, col='category_column')
g.map(sns.histplot, 'numeric_column')

6. Statistical Estimation: Seaborn provides functions for statistical estimation within plots.
# Kernel density estimation plot
sns.kdeplot(df['numeric_column'])

# Violin plot to show the distribution of a numeric variable across categories


sns.violinplot(x='category_column', y='numeric_column', data=df)

7. Additional Functionality: Seaborn includes additional functions for advanced statistical


visualization, such as heatmaps, cluster maps, and regression plots.
# Heatmap for visualizing matrix data
sns.heatmap(data_matrix)
# Cluster map for visualizing hierarchical clustering of data
sns.clustermap(data_matrix)

# Regression plot with confidence intervals


sns.lmplot(x='x_column', y='y_column', data=df)

These are just a few examples of what you can do with Seaborn for creating statistical plots in
Python. Seaborn's simplicity and aesthetics make it a popular choice for data visualization,
especially for exploring and presenting relationships in your data.

____________________________________________________________

5. Interactive Dynamic visualizations - For creating interactive and dynamic


visualizations in Python, you can use libraries such as Plotly, Bokeh, and Plotly Express. These
libraries allow you to create interactive plots with features like zooming, panning, hovering, and
more. Here's an overview of each:
1. Plotly: Plotly is a versatile and powerful library for creating interactive visualizations. It
supports a wide range of plot types, including line plots, scatter plots, bar charts, heatmaps,
and more. Plotly can generate static images or interactive plots that can be embedded in web
applications or Jupyter notebooks.
import plotly.graph_objects as go

# Create a line plot


fig = go.Figure(data=go.Scatter(x=x_data, y=y_data))
fig.show()

2. Bokeh: Bokeh is a Python library that provides interactive plotting capabilities for web
browsers. It allows you to create interactive plots with minimal code using high-level APIs.
Bokeh supports a variety of plot types and provides tools for adding interactivity to your
visualizations.
from bokeh.plotting import figure, show

# Create a scatter plot


p = figure()
p.circle(x_data, y_data)
show(p)

3. Plotly Express: Plotly Express is a high-level interface for Plotly that provides a simplified
API for creating interactive plots. It offers functions for creating a wide range of plot types
with minimal code, making it easy to create interactive visualizations quickly.
import plotly.express as px

# Create a scatter plot


fig = px.scatter(df, x='x_column', y='y_column', color='category_column')
fig.show()

These libraries allow you to create interactive visualizations that enhance data exploration and
presentation. You can customize your plots with features like tooltips, zooming, panning, and more
to provide a rich interactive experience for your audience.

____________________________________________________________
6. SciKit for Machine learning - Scikit-learn, also known as sklearn, is a popular
Python library for machine learning. It provides simple and efficient tools for data mining and data
analysis, built on top of NumPy, SciPy, and Matplotlib. Here's an overview of some of the key
features and functionalities of scikit-learn:
1. Consistent API: Scikit-learn provides a uniform and consistent API for various machine
learning algorithms, making it easy to switch between different models and techniques.
2. Supervised Learning: Scikit-learn includes a wide range of supervised learning algorithms
for classification, regression, and clustering. These algorithms include linear models, support
vector machines, decision trees, random forests, k-nearest neighbors, and more.
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestRegressor

3. Unsupervised Learning: Scikit-learn supports unsupervised learning techniques such as


clustering, dimensionality reduction, and outlier detection. Common algorithms include k-
means clustering, principal component analysis (PCA), and isolation forest.
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.ensemble import IsolationForest

4. Model Evaluation: Scikit-learn provides tools for model evaluation and selection, including
metrics for classification, regression, and clustering tasks. You can use functions like
cross_val_score and GridSearchCV for hyperparameter tuning and model
selection.
from sklearn.model_selection import cross_val_score, GridSearchCV
from sklearn.metrics import accuracy_score, mean_squared_error

5. Data Preprocessing: Scikit-learn includes utilities for data preprocessing, such as scaling,
normalization, encoding categorical variables, and handling missing values.
from sklearn.preprocessing import StandardScaler, OneHotEncoder, Imputer

6. Pipeline: Scikit-learn allows you to create data processing and modeling pipelines, enabling
you to chain multiple processing steps and models together in a single workflow.
from sklearn.pipeline import Pipeline

7. Integration with NumPy and Pandas: Scikit-learn seamlessly integrates with NumPy
arrays and Pandas DataFrames, making it easy to work with data in different formats.
import numpy as np
import pandas as pd

Scikit-learn is well-documented with extensive tutorials and examples, making it accessible for both
beginners and experienced users. It's widely used in academia and industry for a variety of machine
learning tasks, from simple classification problems to complex data analysis pipelines.

____________________________________________________________

You might also like