KEMBAR78
Python Programming | PDF | Parameter (Computer Programming) | Control Flow
0% found this document useful (0 votes)
7 views55 pages

Python Programming

Python is a versatile programming language created by Guido van Rossum in 1991, used for web development, software development, mathematics, and system scripting. It features a simple syntax, extensive libraries, and a large community, making it easy to learn and apply across various domains, though it has limitations in speed and mobile computing. The document also covers Python's REPL environment, variable assignments, and keywords, providing examples and best practices for coding in Python.

Uploaded by

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

Python Programming

Python is a versatile programming language created by Guido van Rossum in 1991, used for web development, software development, mathematics, and system scripting. It features a simple syntax, extensive libraries, and a large community, making it easy to learn and apply across various domains, though it has limitations in speed and mobile computing. The document also covers Python's REPL environment, variable assignments, and keywords, providing examples and best practices for coding in Python.

Uploaded by

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

Introduction to Python:

Python is a popular programming language. It was created by Guido van Rossum, and
released in 1991.

It is used for:

 web development (server-side),


 software development,
 mathematics,
 system scripting.

Need of Python:
 Python can be used on a server to create web applications.
 Python can be used alongside software to create workflows.
 Python can connect to database systems. It can also read and modify files.
 Python can be used to handle big data and perform complex mathematics.
 Python can be used for rapid prototyping, or for production-ready software
development.

Importance of Python:
 Python works on different platforms (Windows, Mac, Linux, Raspberry Pi, etc).
 Python has a simple syntax similar to the English language.
 Python has syntax that allows developers to write programs with fewer lines than
some other programming languages.
 Python runs on an interpreter system, meaning that code can be executed as
soon as it is written. This means that prototyping can be very quick.
 Python can be treated in a procedural way, an object-oriented way or a functional
way.

Advantages of Python:
 Ease of Learning and Use:
Python's simple, readable syntax, resembling natural language, makes it relatively
easy for beginners to learn and understand.
 Extensive Libraries and Frameworks: A vast ecosystem of libraries (e.g., NumPy,
Pandas, Django, Flask) and frameworks simplifies development for various domains
like data science, web development, and machine learning.
 Versatility and Wide Applicability:
Python can be used for a broad range of applications, including web development,
data analysis, artificial intelligence, scientific computing, automation, and scripting.
 Large and Active Community:
Python boasts a large and supportive community, providing ample resources,
documentation, and assistance for developers.
 Improved Productivity:
Its concise syntax and extensive libraries allow developers to write less code and
achieve more, leading to increased productivity.
 Portability:
Python code can run on various platforms (Windows, macOS, Linux) with minimal or
no modifications.

Disadvantages of Python:
 Speed Limitations:
As an interpreted language, Python can be slower than compiled languages like C++
or Java for computationally intensive tasks, especially those requiring high
performance.
 Higher Memory Consumption:
Python's automatic memory management and dynamic typing can lead to higher
memory consumption compared to languages with more explicit memory control.
 Weak in Mobile Computing:
Python is not widely used for mobile application development due to performance and
memory considerations, although frameworks like Kivy exist.
 Global Interpreter Lock (GIL):
The GIL restricts true parallel execution of multiple threads within a single Python
process, potentially limiting performance on multi-core processors for CPU-bound
tasks.
 Runtime Errors:
Python's dynamic typing can lead to runtime errors that might not be caught during
compilation, requiring thorough testing.
 Database Access Layer:
While Python can connect to databases, its native database access layer can be
considered less mature or feature-rich compared to technologies like JDBC or ODBC
for complex enterprise-level interactions.
REPL shell in Python with example
A REPL (Read-Evaluate-Print Loop) is an interactive shell environment that executes a
single line of code at a time and immediately shows the result
. It is a powerful tool for testing small snippets of code, debugging, and exploring
Python's features and libraries.

How to start the Python REPL


1. Open a terminal or command prompt.

2. Type python and press Enter .

3. You will see the Python prompt, which looks like this: >>> .

To exit the REPL: Type exit() or quit() and press Enter . On Windows, you can also
press Ctrl+Z followed by Enter , and on macOS or Linux, use Ctrl+D .

Example of using the Python REPL


Here is a step-by-step example of a REPL session, demonstrating its core features.

text
>>> 2 + 2
4.

Explanation:

 Read: You type 2 + 2 and press Enter .

 Evaluate: Python evaluates the expression 2 + 2 .

 Print: The result, 4 , is printed to the console.

 Loop: The prompt >>> reappears, waiting for your next command.

text
>>> greeting = "Hello, REPL!"
>>> greeting
'Hello, REPL!'
Explanation:

 You can declare and assign variables, and they are immediately stored in memory for
the current session.

 Typing the variable's name and pressing Enter prints its value.

text
>>> def multiply(a, b):
... return a * b
...
>>> multiply(5, 6)
30

Explanation:

 For multi-line statements like functions or loops, the prompt changes to ... to indicate
that Python is expecting more code.

 Pressing Enter on a blank line ends the multi-line statement.

 The function can then be called and tested immediately.

text
>>> import math
>>> math.sqrt(16)
4.0
>>> math.pi
3.141592653589793

Explanation:

 Modules can be imported and their functions and attributes can be used immediately.

 This is useful for quickly experimenting with libraries.

text
>>> my_list = [10, 20, 30, 40]
>>> my_list.append(50)
>>> my_list
[10, 20, 30, 40, 50]

Explanation:

 You can interactively modify data structures like lists and dictionaries and see the
changes reflected immediately.

REPL features:
 Command History: You can press the up and down arrow keys to cycle through
previously executed commands.

 Tab Completion: If you type the beginning of a variable, function, or module name and
press the Tab key, the REPL will try to complete the name for you. Pressing Tab again
will show all possible options.

 help() function: To get instant documentation for any function, type help() followed by
the item you want to inspect. For example, help(str) .

How to run a Python Script:


There are several ways to run a Python script, including using the command line, an
Integrated Development Environment (IDE), or a code editor
. The most common method is using your system's terminal or command prompt.

1. Run a script from the command line


This is the most direct and universally applicable method.

Steps

1. Save your file: Create a file with a .py extension (e.g., hello.py ).

2. Open a terminal:

 Windows: Open the Command Prompt or PowerShell by searching


for cmd or powershell in the Start menu.

 macOS/Linux: Open the Terminal app.


3. Navigate to the file's directory: Use the cd (change directory) command to move to the
folder where you saved your script. For example:

sh
cd C:\Users\YourName\Documents\python_projects

4. Execute the script: Run the script by typing python followed by the filename. On some
systems, especially Linux and macOS, you may need to use python3 .

sh
python hello.py

Your script's output will appear directly in the terminal.


Example script: hello.py

python
print("Hello, world!")

2. Run a script in an IDE or code editor


IDEs like PyCharm and code editors like Visual Studio Code offer built-in features to run
scripts with a single click.

Steps in Visual Studio Code (VS Code)

1. Open the file: Open your .py file in VS Code.

2. Click the "Run" button: Click the small green "play" arrow in the top-right corner of the
editor. This will execute the script in the integrated terminal.

3. Use the command palette: Alternatively, you can open the Command Palette
(Ctrl+Shift+P) and select Run Python File in Terminal .

3. Interactive Mode (REPL)


If you want to run Python code line-by-line for testing or exploration, you can enter the
interactive mode (Read-Eval-Print-Loop).
Steps

1. Open a terminal and type python (or python3 ) and press Enter.

2. Enter Python code at the >>> prompt.

python
>>> print("Hello from the REPL!")
Hello from the REPL!
>>> 2 + 5
7

3. Exit the REPL: Type exit() and press Enter.

Variables in python:
In Python, a variable is a symbolic name that acts as a container for storing data.
Variables allow you to label data with a descriptive name, which makes your code
easier to read, maintain, and reuse.

Creating and assigning variables


Unlike some other programming languages, Python is dynamically typed. You don't
need to declare a variable's type before using it; a variable is created the moment you
first assign a value to it using the = assignment operator.

Example

python
# An integer variable
age = 30

# A string variable
name = "Jane Doe"

# A floating-point variable
price = 19.99

# A boolean variable
is_active = True
# You can print variables to see their values
print(name)
print(age)

Key characteristics of Python variables


 Dynamic Typing: The type of a variable is inferred from the value you assign to it and
can be changed later simply by assigning a new value of a different type.

python
x=5 # x is an integer
x = "Hello" # Now x is a string

 Case-sensitive: Variable names are case-sensitive. my_variable , My_Variable ,


and MY_VARIABLE are all considered different variables.

 Reference-based: Variables in Python hold references to objects in memory, not the


objects themselves. This is important to remember when dealing with complex data
types like lists.

python
a = [1, 2, 3]
b=a # b references the same list object as a
b.append(4)
print(a) # Output: [1, 2, 3, 4]

 No explicit declaration: You do not need to use special keywords to declare a variable.
The act of assigning a value creates the variable.

Naming conventions and rules


To create a valid variable name in Python, follow these rules:

 It must start with a letter (a-z, A-Z) or an underscore ( _ ).


 It cannot start with a number.

 It can only contain alpha-numeric characters and underscores ( A-z , 0-9 , and _ ).

 It cannot be a Python keyword (e.g., if , for , class ).

Good practices:

 Use meaningful names: Names should describe the variable's purpose


(e.g., user_name instead of un ).

 Use snake_case: The standard convention is to use lowercase words separated by


underscores for multi-word variables (e.g., first_name ).

Common data types for variables :


Python variables can store a wide variety of data types, including:

 int : Whole numbers ( age = 25 ).

 float : Numbers with a decimal point ( price = 19.99 ).

 str : Text enclosed in single or double quotes ( name = "John" ).

 bool : Boolean values, either True or False ( is_logged_in = False ).

 list : An ordered, mutable collection of items ( fruits = ["apple", "banana"] ).

 dict : An unordered collection of key-value pairs ( student = {"name": "Rohit", "age": 36} ).

Variable scope :
The scope of a variable determines where in your program it can be accessed.

 Local variables are defined inside a function and are only accessible within that
function.

 Global variables are defined outside of any function and can be accessed from
anywhere in the program.

Assignments in python:
In Python, an assignment is the process of creating a variable and giving it a value. The
equal sign ( = ) is the main assignment operator, which binds the variable name on its
left to the data object on its right.
Basic assignment:
The most common form of assignment is giving a single variable a single value.

Example:

python
# A new variable `name` is assigned the string "Alice"
name = "Alice"
print(name) # Output: Alice

# An existing variable can be reassigned a new value, even a different type


name = 30
print(name) # Output: 30

Multiple assignments:
Python offers several shortcuts for assigning values to multiple variables
simultaneously.

Assign a single value to multiple variables:


Use a chained assignment to set multiple variables to the same value in one line. This
assigns the same object reference to all variables.

Example:

python
x = y = z = 100
print(x, y, z) # Output: 100 100 100

Assign multiple values to multiple variables:


Use parallel assignment to map values from an iterable (like a tuple or list) to a
sequence of variables. The number of variables must match the number of values.

Example:

python
a, b, c = 1, 2, 3
print(a, b, c) # Output: 1 2 3

# This is also the standard Python way to swap values


a, b = b, a
print(a, b) # Output: 2 1

Augmented assignments:
These are a shorthand for performing an operation on a variable and then assigning the
result back to that variable.

Common augmented assignment operators include:

 += (addition assignment): x += 5 is equivalent to x = x + 5

 -= (subtraction assignment): x -= 5 is equivalent to x = x - 5

 *= (multiplication assignment): x *= 5 is equivalent to x = x * 5

 /= (division assignment): x /= 5 is equivalent to x = x / 5

 **= (exponentiation assignment): x **= 2 is equivalent to x = x ** 2

Example:

python
counter = 1
counter += 1
print(counter) # Output: 2

total = 100
total -= 25
print(total) # Output: 75
Use code with caution.

Key facts about assignment in Python


 Dynamic Typing: You do not need to declare a variable's type. The variable's type is
inferred from the value you assign to it.

 Case Sensitivity: Variable names are case-sensitive, so myVar and myvar are treated
as two different variables.
 Object References: In Python, a variable is not a container for data but a reference to a
data object stored in memory. When you assign y = x , both variables reference
the same object. Reassigning x to a new value will not change y , but modifying a
mutable object (like a list) through one variable will be reflected when accessing it with
the other.

Keywords:
Keywords in Python are reserved words that hold special meaning to the
Python interpreter. These words are fundamental to the syntax and structure
of the language, and therefore, they cannot be used as identifiers (names for
variables, functions, classes, or other user-defined entities).

Characteristics of Python Keywords:


 Reserved:
They are pre-defined by the Python language and cannot be redefined or used for
other purposes.
 Case-sensitive:
Python keywords are case-sensitive. For example, True is a keyword, but true is not.
 Define Syntax and Structure:
They dictate how Python code should be written and interpreted, enabling
functionalities like conditional statements, loops, function definitions, and class
declarations.
Examples of Python Keywords:
 Control Flow: if, else, elif, for, while, break, continue, pass
 Function and Class Definition: def, class, lambda, return, yield
 Module Management: import, from, as
 Exception Handling: try, except, finally, raise, assert
 Boolean and Null Values: True, False, None
 Variable Scope: global, nonlocal
 Context Management: with
 Logical Operators: and, or, not
 Membership and Identity: in, is
 Object Deletion: del
 Asynchronous Programming (Python 3.5+): async, await
You can programmatically list all keywords in a specific Python version by
importing the keyword module and accessing keyword.kwlist

Input & Output :


In Python, you can perform basic input from the user using the input() function and
produce output to the console using the print() function.

Input:
The input() function prompts the user for text and returns it as a string.

Syntax: input(prompt)

 The prompt is an optional string that is displayed to the user before they enter their
input.

Example 1: Basic text input

# The input() function displays a message and waits for user input
name = input("Please enter your name: ")
print("Hello,", name)

Example 2: Numerical input


By default, input() returns a string. To work with numbers, you must convert the string to
an integer or float using int() or float() .

# The input is first a string, so it must be converted


age_string = input("How old are you? ")
age_number = int(age_string)

# Perform a calculation with the number


print("You will be", age_number + 1, "years old next year.")
Example 3: Multiple inputs on one line
You can accept multiple values on a single line by using the split() method, which
separates the input string based on whitespace.

# Read two space-separated numbers


a, b = input("Enter two numbers: ").split()

# Convert the strings to integers and print their sum


print("The sum is:", int(a) + int(b))

Output:
The print() function displays information to the console.

Syntax: print(object(s), sep=separator, end=end_char)

 object(s) : One or more values to be printed, separated by commas.

 sep (optional): A string to separate the values. The default is a space ( ' ' ).

 end (optional): A string to append at the end of the output. The default is a newline
character ( '\n' ).

Example 1: Basic output


You can print strings, variables, and expressions.

greeting = "Hello, World!"


print(greeting)

x = 10
y = 20
print("The sum of x and y is:", x + y)
Example 2: Customizing output
Use the optional sep and end arguments to format the output.

# Print items with a custom separator


print("apple", "banana", "cherry", sep=", ")

# Print on the same line by changing the end character


print("This is on the first line.", end=" ")
print("This continues on the same line.")

A combined example:

Here is a complete program that uses both input and output to interact with the user.

# Get the user's name as a string


name = input("Enter your name: ")
# Get the user's favorite number and convert it to an integer
fav_number_str = input("What is your favorite number? ")
fav_number = int(fav_number_str)

# Print a formatted output using an f-string


print(f"Hello, {name}!")
print(f"Your favorite number is {fav_number}, and doubling it gives you {fav_number * 2}.")

# Example output with sample user input:


# Enter your name: Alice
# What is your favorite number? 7
# Hello, Alice!
# Your favorite number is 7, and doubling it gives you 14.

Indentation :
Indentation in Python refers to the leading whitespace (spaces or tabs) at the
beginning of a line of code. Unlike many other programming languages that
use curly braces or other delimiters to define code blocks, Python uses
indentation as a fundamental part of its syntax to indicate the structure and
scope of code blocks.

Key aspects of Python indentation:


 Defining Code Blocks:
Indentation is crucial for defining blocks of code associated with control structures
like if statements, for loops, while loops, function definitions, and class definitions. All
statements belonging to the same block must have the same level of indentation.
 Significance:
Indentation in Python is not merely for readability; it is syntactically enforced. Incorrect
or inconsistent indentation will lead to IndentationError or TabError during execution.
 Consistency:
Within a single code block, the number of spaces or tabs used for indentation must be
consistent. While the Python interpreter allows varying indentation amounts between
different blocks, the conventional and recommended practice is to use a consistent
number of spaces (commonly four spaces) for each level of indentation throughout the
entire codebase.
 Spaces vs. Tabs:
While Python supports both spaces and tabs for indentation, the official Python style
guide (PEP 8) strongly recommends using spaces over tabs. Mixing spaces and tabs
within the same file can lead to unexpected indentation issues.
 First Line:
The first line of a Python script or module should not be indented, as it is considered
the top-level scope.

Types of operators in python:

Python uses various types of operators to perform operations on values and variables.
These include:

 Arithmetic operators for basic mathematical calculations like addition ( + ), subtraction


( - ), multiplication ( * ), division ( / ), modulus ( % ), exponentiation ( ** ), and floor division
( // ).

 Assignment operators to assign values to variables, such as = and shorthand


operators like += and -= .

 Comparison (or relational) operators to compare values and return True or False ,
including == , != , > , < , >= and <= .

 Logical operators ( and , or , not ) to combine conditional statements.

 Bitwise operators that operate on binary representations of integers, such


as & , | , ^ , ~ , << , and >> .

 Identity operators ( is , is not ) to check if variables refer to the same object in memory.

 Membership operators ( in , not in ) to test if a value is present in a sequence

Types of expressions in python:


In Python, an expression is a combination of variables, literals, and operators that the
interpreter evaluates to produce a single value. The types of expressions are generally
categorized by the kind of operation they perform or the value they produce.

Arithmetic expressions
Arithmetic expressions perform mathematical calculations and evaluate to a numerical
value.

 Addition ( + ): 5 + 3 results in 8 .

 Multiplication ( * ): y * 2 results in 10 if y is 5 .

 Division ( / ): 10 / 5 results in 2.0 , a float.

 Floor Division ( // ): 9 // 2 results in 4 , an integer.

Relational (comparison) expressions


These expressions use comparison operators to test the relationship between two
values. They always evaluate to a boolean value: True or False .

 Equal to ( == ): x == 10 is True if x is 10 .

 Not equal to ( != ): a != b is True if a and b have different values.

 Greater than or equal to ( >= ): age >= 18 might be used to check if a person is old
enough.

Logical expressions
Logical expressions combine two or more relational or boolean expressions using
logical operators ( and , or , not ) and produce a boolean result.

 and : x < 5 and x < 10 is True only if both conditions are met.

 or : x < 5 or x < 4 is True if either condition is met.

 not : not(x < 5 and x < 10) inverts the result of the expression inside the parentheses.

Assignment expressions (The "walrus operator")


Introduced in Python 3.8, the assignment expression ( := ) allows you to assign a value
to a variable and return that value as part of a larger expression.

 Example: if (n := len(a)) > 10: print(f"List is too long ({n} elements)") .


Conditional expressions
Also known as a ternary operator, this allows for a compact, single-line if-else
statement.

 Syntax: value_if_true if condition else value_if_false

 Example: max_number = x if x > z else z assigns the greater of x or z to max_number .

Comprehension expressions
This family of expressions offers a concise way to build data structures like lists, sets,
and dictionaries from an iterable.

 List comprehension: [x for x in range(10)] creates a list of numbers from 0 to 9.

 Dictionary comprehension: {x: x**2 for x in range(5)} creates a dictionary mapping


numbers to their squares.

 Generator expressions: (x for x in range(10)) returns a generator object, which creates


values on the fly instead of storing them all in memory.

Other notable expression types:


 Constant expressions: An expression that consists of a literal value, such
as 5 or 'hello' .

 Integral expressions: These produce integer results, even if the operands are not all
integers, due to automatic type conversion.

 Bitwise expressions: Used for low-level manipulation of data at the bit level.

Conditional statements in python:


In Python, conditional statements allow code to run only when a specified condition is
met. The primary types are if , if...else , and if...elif...else . Python uses indentation and a
colon to structure these blocks.

 if statement: Executes a code block if the condition is True .

if condition:
# Code to execute
 if...else statement: Provides an alternative block for when the condition is False .

if condition:
# Code if True
else:
# Code if False

 if...elif...else statement: Checks multiple conditions in order, executing the first one that
is True .

if condition1:
# Code if condition1 is True
elif condition2:
# Code if condition2 is True
else:
# Code if none are True

 Nested if statements: Allows for placing if statements within other conditional blocks
for more complex logic.

While Break Statement:


In Python, the break statement is used to exit a loop prematurely, regardless of
whether the loop's condition has been met or not. When a break statement is
encountered within a while loop, the loop terminates immediately, and program
execution continues with the statement immediately following the loop.
This functionality is particularly useful in situations where a specific condition
arises within the loop that necessitates its termination before the
original while condition becomes false.
Here is an example demonstrating the use of break within a while loop:
Python
count = 0
while True: # This creates an infinite loop
print(f"Current count: {count}")
count += 1
if count >= 5:
print("Count reached 5, breaking the loop.")
break # Exit the loop when count is 5 or greater

print("Loop finished.")
Explanation:
 An infinite while True loop is initiated.
 Inside the loop, the count is printed and incremented.
 An if statement checks if count is greater than or equal to 5.
 If the condition in the if statement is met, a message is printed, and the break statement
is executed, causing the while loop to terminate.
 After the loop terminates, the "Loop finished." message is printed.
Key points about break in while loops:
 It provides a way to exit a loop based on dynamic conditions that might not be part of
the initial while condition.
 It is often used within an if statement to conditionally terminate the loop.
 When break is executed, the else block associated with a while loop (if present) will not be
executed.

Continue and Pass statement in python:


continue and pass are both keywords that alter the flow of a program, but they serve
completely different purposes.

continue

The continue statement is used exclusively inside loops ( for or while ) to skip the rest of
the code in the current iteration and immediately move to the next iteration.

How it works:
 When the Python interpreter encounters continue , it stops executing the rest of the
loop's current code block.

 It then jumps back to the top of the loop to begin the next iteration.

Example:
This code prints every number from 0 to 4, except for 2.

for number in range(5):


if number == 2:
continue # Skips the rest of the loop for this iteration
print(number)

Output:

0
1
3
4

pass

The pass statement is a null operation—it does nothing. It is used as a placeholder


where a statement is syntactically required but no action is needed.

How it works:

 The interpreter executes pass and then proceeds to the next line of code. It does not
alter the flow of the loop or conditional block.

 It is most useful for defining a code block that you intend to fill in later to avoid
a SyntaxError .

Example:
This code includes a pass statement inside the if condition. The program executes
the pass and then continues to the next line, so all numbers are printed.

for number in range(5):


if number == 2:
pass # Does nothing; the program continues
print(number)

Output:

0
1
2
3
4
Difference between Continue & Pass Statement:

Feature continue pass


Action Skips the rest of the code in Does nothing; it is a placeholder.
the current loop iteration.

Effect on loop Jumps to the beginning of No effect on the loop's flow; execution
the next iteration. simply moves to the next statement.

Usage Exclusively used within Can be used anywhere a statement is


loops ( for and while ). syntactically required, such as in functions,
classes, and conditional blocks.

Primary Use Efficiently skipping items in Temporarily filling empty code blocks to
Case a loop that meet a certain avoid SyntaxError , especially during
condition.
code development.

Data Structure Lists in python


In Python, a data structure is a format for organizing and storing data in a way that
enables efficient access and manipulation. Python includes powerful built-in data
structures and also allows for the implementation of custom, or user-defined,
structures.

Built-in data structures:


Lists

 Definition: An ordered, mutable collection of items. A list can contain elements of


different data types.

 Syntax: Created with square brackets [] .

 Example:

my_list = [10, "hello", True, 3.14]


my_list.append(50)
print(my_list) # Output: [10, 'hello', True, 3.14, 50]

 Key features:

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

o Ordered: Elements have an index, and their order is maintained.

o Efficient operations: Fast for adding to the end with append() , but insertions and
deletions from the middle can be slower.

Tuples

 Definition: An ordered, immutable collection of items.

 Syntax: Created with parentheses () .

my_tuple = (10, "hello", True)


# my_tuple[0] = 20 # This will raise an error because tuples are immutable
print(my_tuple[1]) # Output: hello

 Key features:

o Immutable: Cannot be modified after creation, making them useful for data that should
not change.

o Ordered: Like lists, elements have a defined order and index.

o Performance: Generally use less memory and are faster than lists.

Dictionaries

 Definition: An unordered, mutable collection of unique key-value pairs.

 Syntax: Created with curly braces {} and colons to separate keys from values.

 Example:

my_dict = {"name": "Alice", "age": 30}


print(my_dict["name"]) # Output: Alice
my_dict["city"] = "New York"
print(my_dict) # Output: {'name': 'Alice', 'age': 30, 'city': 'New York'}
 Key features:

o Mutable: Keys and values can be added, changed, or removed.

o Efficient retrieval: Optimized for quickly retrieving a value based on its key.

o Keys must be unique: Each key in a dictionary must be unique.

Sets

 Definition: An unordered, mutable collection of unique elements.

 Syntax: Created with curly braces {} or the set() constructor.

 Example:

my_set = {1, 2, 3, 2}
print(my_set) # Output: {1, 2, 3} (duplicate '2' is removed)
my_set.add(4)
print(my_set) # Output: {1, 2, 3, 4}

 Key features:

o Unique elements: Duplicates are not allowed.

o Efficient membership testing: Very fast to check if an element is present in the set.

o No defined order: Elements are not stored in any specific sequence.

User-defined data structures


These more complex data structures are typically created using Python's built-in types
(like lists) or custom classes.

Stacks

 Principle: Last-In, First-Out (LIFO).

 Operations: push (add to the top) and pop (remove from the top).
 Implementation: Can be implemented using a Python list, with append() for push
and pop() for pop.

Queues

 Principle: First-In, First-Out (FIFO).

 Operations: enqueue (add to the end) and dequeue (remove from the front).

 Implementation: Can be implemented using collections.deque for efficient appends and


pops from both ends.

Linked lists

 Principle: A sequence of nodes, where each node contains data and a reference to the
next node.

 Implementation: Not a built-in Python type; it's typically implemented with a custom
class for the node and another for the list.

Trees

 Principle: A hierarchical, non-linear data structure with a root, nodes, and branches.

 Implementation: A common form is a binary search tree, which is implemented with


classes for nodes that point to "left" and "right" child nodes.

How to choose the right data structure:


The best data structure depends on your specific needs:

 For ordered, modifiable data: Use a list.

 For ordered, unchangeable data: Use a tuple.

 For fast lookups using unique keys: Use a dictionary.

 For a collection of unique items where order doesn't matter: Use a set.

 For specific LIFO or FIFO behavior: Implement a stack or queue, respectively.

Slicing methods in python:


In Python, slicing is a powerful method for extracting a portion (a "slice") of a sequence,
such as a list, tuple, or string. This technique is both concise and efficient for data
manipulation. You can perform slicing using the square bracket notation [] or with the
built-in slice() function.

The fundamental syntax for slicing is sequence[start:stop:step] .

 start : The index where the slice begins (inclusive). If omitted, it defaults to the beginning
of the sequence (index 0).

 stop : The index where the slice ends (exclusive). The element at this index is not
included. If omitted, it defaults to the end of the sequence.

 step : The interval between elements. If omitted, it defaults to 1, selecting every element.
A negative step reverses the order of the slice.

Basic slicing with bracket notation []

This is the most common and versatile method for slicing.

Example data : Let's use a list of numbers for the following examples:

my_list = [10, 20, 30, 40, 50, 60, 70, 80, 90]

1. Slice with start and stop Extracts a subsequence from the start index up to (but not
including) the stop index.

# Get elements from index 2 up to index 5


print(my_list[2:5])
# Output: [30, 40, 50]
2. Omit start Gets all elements from the beginning of the sequence up to the stop
index.

# Get the first three elements


print(my_list[:3])
# Output: [10, 20, 30]

3.Omit stop Gets all elements from the start index to the end of the sequence.

# Get all elements from index 6 to the end


print(my_list[6:])
# Output: [70, 80, 90]
4. Slice with step Retrieves elements at a specified interval.

# Get every second element from the list


print(my_list[::2])
# Output: [10, 30, 50, 70, 90]

5. Reverse a sequence

# Reverse the list


print(my_list[::-1])
# Output: [90, 80, 70, 60, 50, 40, 30, 20, 10]

Use negative indices, Negative indices count from the end of the sequence. For
example, -1 refers to the last element.

# Get the last three elements


print(my_list[-3:])
# Output: [70, 80, 90]

# Get all but the last two elements


print(my_list[:-2])
# Output: [10, 20, 30, 40, 50, 60, 70]

The slice() function


The slice() function creates a reusable slice object. This is useful when you want to
apply the same slicing logic in multiple places or pass it as an argument.

Syntax: slice(start, stop, step)

Example

my_list = ['apple', 'banana', 'cherry', 'date', 'elderberry']

# Create a slice object


a_slice = slice(1, 4)
# Apply the slice object to the list
print(my_list[a_slice])
# Output: ['banana', 'cherry', 'date']

Functions in python:
In Python, a function is a named, reusable block of code that performs a specific task.
Using functions makes your code more organized, readable, and modular, and it
prevents you from having to repeat the same code.

There are two main types of functions in Python:

 Built-in functions: These are standard functions that are always available, such
as print() , len() , and range() .

 User-defined functions: These are functions that you create yourself to suit your specific
needs.

How to create and call a user-defined function:


You define a function using the def keyword, followed by a name and parentheses () .
Any code inside the function must be indented.

def function_name(parameter1, parameter2):


"""(Optional) A docstring to explain what the function does."""
# Function body: code to perform a task
return expression # (Optional) Returns a value to the caller
Example:
The following function, greet , takes one parameter, name , and prints a greeting.

def greet(name):
print(f"Hello, {name}!")

# Call the function with an argument


greet("Alice")
# Output: Hello, Alice!

Function arguments:
Arguments are the values passed into a function when it is called. Python supports
several ways to handle arguments.

Positional arguments
The arguments are assigned to parameters based on their position in the function call.
def add_numbers(a, b):
return a + b

add_numbers(5, 3) # a=5, b=3. Returns 8.

Keyword arguments
You can pass arguments by explicitly naming the corresponding parameter, which
allows you to put them in any order.

def introduce(name, city):


print(f"{name} is from {city}.")

introduce(city="Paris", name="Jean")
# Output: Jean is from Paris.

Default arguments
You can set a default value for a parameter. If no argument is passed for that
parameter, the default value is used.

def say_hello(name="World"):
print(f"Hello, {name}!")

say_hello("Bob") # Output: Hello, Bob!


say_hello() # Output: Hello, World!
Arbitrary arguments ( *args and **kwargs )

 *args allows a function to accept a variable number of non-keyword (positional)


arguments, which are received as a tuple.

 **kwargs allows a function to accept a variable number of keyword arguments, which are
received as a dictionary.

def print_args(*args, **kwargs):


print("Positional args:", args)
print("Keyword args:", kwargs)
print_args(1, 2, 3, city="New York", occupation="Engineer")
# Output:
# Positional args: (1, 2, 3)
# Keyword args: {'city': 'New York', 'occupation': 'Engineer'}

Anonymous (lambda) functions:


A lambda function is a small, single-expression anonymous function. It is defined using
the lambda keyword and can take any number of arguments.

lambda arguments: expression

Example

# A lambda function to add two numbers


add = lambda x, y: x + y
print(add(2, 3))
# Output: 5

Fruitful functions in python:


In Python, a fruitful function is a function that performs a task and returns a value to the
caller. The returned value can be stored in a variable, used in an expression, or passed
as an argument to another function. This contrasts with a "non-fruitful" or "void" function,
which executes a series of steps but does not return a usable value.

Working of Fruitful Functions:


The key to a fruitful function is the return statement.

 When a return statement is executed, the function immediately terminates and sends
the specified value back to the point where it was called.

 Any code after the return statement within the function is "dead code" and will not be
executed.

 A function can have multiple return statements, but only one will be executed
depending on the logic and control flow.
Example: A simple fruitful function

The following function calculate_area is fruitful because it computes a value and returns
it.

def calculate_area(length, width):


"""
Calculates the area of a rectangle.
"""
area = length * width
return area

# Call the fruitful function and store the result


rectangle_area = calculate_area(5, 8)

# Print the value returned by the function


print(f"The area of the rectangle is: {rectangle_area}")

# Output:
# The area of the rectangle is: 40

Fruitful functions offer flexibility by allowing you to return more than one value, which
Python handles by packing the values into a tuple.

Example: Returning multiple values

Fruitful functions vs. void functions:


The distinction between fruitful and void functions is all about the return value.

Feature Fruitful Function Void Function

Returns a Yes, using the return <value> statement. No, it performs an action and does not return a usable
value value.

Return value The explicit value specified after It implicitly returns None , a special Python value
the return keyword, which can be of any data representing the absence of a value.
type.
Purpose To provide a result that can be used for further To perform an action or cause a side effect, such as
computations. printing to the console or modifying a data structure.

Syntax Always contains a return May or may not contain a return statement. If it does,
<value> statement. it's a bare return .

Example: A non-fruitful (void) function

The greet function below is a void function because it only prints a message and does
not return a value.

def greet(name):
"""
Prints a greeting to the console.
"""
print(f"Hello, {name}!")

# Call the void function


greet("Alice")

# Trying to capture the return value will result in None


result = greet("Bob")
print(f"The value of 'result' is: {result}")

# Output:
# Hello, Alice!
# Hello, Bob!
# The value of 'result' is: None

Modules and its creation in python:


A Python module is a file containing Python code, such as functions, classes, and
variables, that can be used in other programs. Modules help to organize code into
reusable, logical units, which makes it more readable, maintainable, and efficient.

Python has two main types of modules:

 Built-in modules: A vast standard library of pre-defined modules, like math and os , is
bundled with every Python installation.
 User-defined modules: Custom modules that you create to organize your own
functions and classes for specific projects.

How to create a module:


To create a module, simply write and save Python code in a file with a .py extension.
For instance, a file named calculator.py automatically becomes a module
named calculator .

Example: calculator.py

def add(x, y):


"""Returns the sum of two numbers."""
return x + y

def subtract(x, y):


"""Returns the difference of two numbers."""
return x - y

def multiply(x, y):


"""Returns the product of two numbers."""
return x * y

Best practices for using modules:


 Place imports at the top: Put all import statements at the beginning of your file for
clarity.

 Group and order imports: Separate your imports into three groups: standard library,
third-party libraries, and local project modules. Within each group, sort alphabetically.

 Use if __name__ == "__main__": : If your module contains runnable code for testing, place
it inside this block. This code will only execute when the file is run directly, not when it's
imported by another script.

Packages vs. modules:


While often used interchangeably, "module" and "package" have distinct meanings:

 A module is a single .py file.


 A package is a directory that organizes related modules into a hierarchy. A directory
becomes a package if it contains an __init__.py file (though this is no longer strictly
required for simple packages in modern Python).

Name spacing in python:


In Python, a namespace is a system that ensures all object names are unique and can
be used without conflict. It is essentially a mapping from names to objects, much like a
dictionary. The concept of name spacing prevents naming conflicts and helps organize
code, especially in large programs with multiple modules, classes, and functions.

How namespace works:


Python's scope resolution system, known as the LEGB rule, dictates the order in which
namespaces are searched for a given name.

 L: Local—The innermost scope. It holds names defined within the current function,
including its arguments.

 E: Enclosing—For nested functions, this is the scope of the outer (enclosing) function. A
name not found in the inner function's local scope is searched for here.

 G: Global—The module-level scope. This contains all names defined in the main body
of a script or module.

 B: Built-in—The outermost scope. It contains Python's pre-assigned, built-in names


like print() , len() , and range()

Types of namespaces in Python:


Local namespace

 Created: When a function is called.

 Contains: The names defined inside that function, including its parameters.

 Lifetime: Lasts only for the duration of the function's execution. When the function
returns, the local namespace is destroyed.

Global namespace
This namespace is created when a module is imported or a script starts. It contains
names defined at the top level of the module and exists until the interpreter stops.

Enclosing namespace

This namespace is associated with outer functions when functions are nested. It
contains names in the outer function that are available to inner functions and lasts as
long as the outer function is running.

Built-in namespace

Created when the Python interpreter begins, this namespace holds all of Python's
standard built-in functions and objects. It persists for the entire duration of the
interpreter's execution.

Import statement and from. import statement:


In Python, import and from ... import are two primary ways to bring code from one
module into another. The main difference lies in how the imported code is made
accessible within your program's namespace.
 A name space is a system that ensures all names in a program are unique by
associating them with a specific module.

import module_name

This statement imports the entire module, and to access any of its contents, you must
use the module's name as a prefix.

Syntax:
import module_name

Example:

To use the sqrt() function from the math module, you would write math.sqrt() .

import math

# Use the square root function from the 'math' module


print(math.sqrt(25))

# Access the 'pi' constant


print(math.pi)
Pros:
 Avoids naming conflicts: The module prefix prevents names from clashing with functions
or variables in your own code.

 Improves readability: It is always clear where a function or variable originated from,


making the code easier to understand.

Cons:

 Can be more verbose if you use many different functions from the same module.

from module_name import item

This statement imports specific items (functions, classes, or variables) from a module
directly into your current namespace. You can then use the item's name without a
prefix.

Syntax:
from module_name import item1, item2

Example:

To use the sqrt() function directly without the math. prefix.

from math import sqrt, pi


# You can now use 'sqrt' and 'pi' directly
print(sqrt(25))
# You can use the constant 'pi' directly
print(pi)

Pros:

 More concise: The code can be shorter and less repetitive, especially when calling a
specific item multiple times.

 Clearer intent: It explicitly states which parts of a module you intend to use.

Cons:

 Risk of naming conflicts: Importing multiple names directly can cause clashes if your
code or other imported modules use the same name.
 Less readable (for many imports): If you import many items, it can become less obvious
where each item originated.

from module_name import *

This variation imports all public items from a module into the current namespace.

Syntax:
from module_name import *

Example:

from math import *


print(sqrt(25))
print(pi)

Key differences:
Feature import module_name from module_name import item

Code Access All contents of the module are available, but must Only the specified items are available and can be
be accessed with a prefix ( module_name.item ). accessed directly without a prefix.

Namespace Adds a single name ( module_name ) to the Adds multiple specific names ( item1 , item2 ) to
Impact current namespace. the current namespace.

Readability High; the origin of each function or variable is Can be high if only a few items are imported, but
always explicit. decreases if many items are pulled into the
namespace.

Best For General use, or when importing many items from Importing only one or two frequently used items
a module to prevent name conflicts. from a module

Python packages:
A Python package is a directory that contains a collection of related modules and a
special __init__.py file, which tells Python to treat the directory as a package. Packages
are a fundamental way to organize, reuse, and share code in a hierarchical structure,
especially in large projects.

Standard library vs. third-party packages:


There are two main types of packages you will encounter in Python:
 Standard library: A comprehensive set of modules and packages that come pre-
installed with every standard Python distribution. You can rely on these libraries being
available on any system running Python, and they cover many common programming
tasks like file I/O, internet protocols, and data structures.

 Third-party packages: Libraries developed and published by the Python community.


They can be installed separately to extend Python's functionality far beyond the
standard library. The Python Package Index (PyPI) is the official repository for hundreds
of thousands of these packages, covering a vast range of applications from web
development to machine learning.

How to use third-party packages:


The most common way to install and manage third-party packages is by using a
package manager like pip in conjunction with a virtual environment.

1. Create a virtual environment

Virtual environments create an isolated environment for a project, so you can manage a
project's dependencies without affecting other projects or the global Python installation.

# Create a new virtual environment in a folder named 'my_project_env'


python -m venv my_project_env

2. Activate the virtual environment

You must activate the virtual environment to ensure that any packages you install are
added to it and not your global Python installation.

 On macOS and Linux:

source my_project_env/bin/activate
 On Windows:

my_project_env\Scripts\activate

3. Install packages with pip


Once the environment is active, use the pip install command to download and install
packages from PyPI. The command prompt or terminal will show the name of the active
environment, like (my_project_env) .

# Install a package like 'requests'


pip install requests

4. Use the package in your code

You can now import the installed package into your Python script and use its
functionality.
import requests
response = requests.get('https://example.com')
print(response.status_code)

Popular Python packages:

The Python ecosystem offers packages for almost any task. Some of the most widely
used ones include:

Data science and machine learning:

 NumPy: Fundamental package for numerical computing with large, multi-dimensional


arrays and matrices.

 Pandas: Provides powerful, flexible data structures for data analysis and manipulation.

 SciPy: A library of functions for scientific and technical computing.

 Scikit-learn: Offers simple and efficient tools for machine learning, including
classification, regression, and clustering.

 TensorFlow / PyTorch: Deep learning frameworks used for building complex neural
networks.

Web development:

 Django: A full-featured, "batteries-included" framework for building complex web


applications.

 Flask: A lightweight and minimalist web framework for smaller applications and APIs.
 Requests: An elegant and simple HTTP library for making web requests.

Data visualization:

 Matplotlib: A versatile library for creating static, animated, and interactive


visualizations.

 Seaborn: Built on top of Matplotlib, it provides a high-level interface for drawing


attractive statistical graphics.

Web scraping:

 BeautifulSoup: A library for pulling data out of HTML and XML files.

 Scrapy: An open-source framework for web crawling and data extraction.

Other applications:

 PyGame: A set of modules for writing video games and multimedia applications.

 Tkinter: Python's standard GUI toolkit for creating desktop applications.

 NLTK: The Natural Language Toolkit for working with human language data.

Introduction to pip in python:


As the standard package manager for Python, pip is a command-line tool that allows
you to install and manage external software packages and libraries. These packages
are sourced primarily from the Python Package Index (PyPI), a vast online repository of
community-contributed software. With pip, you can extend the capabilities of your
Python projects by adding functionality that is not included in the Python Standard
Library.
How pip works:
Pip simplifies the process of managing dependencies, which are the other packages a
project needs to function correctly.

 Installation: When you install a package, pip automatically finds it on PyPI, downloads
it, and installs it in your Python environment. For example, to install the requests library
for making web requests, you would run pip install requests .
 Dependency resolution: If a package you want to install has its own dependencies, pip
automatically identifies and installs those as well, ensuring everything works together.

 Package isolation with virtual environments: To prevent conflicts between projects


that might require different versions of the same package, pip is often used within an
isolated virtual environment (created with tools like venv ). This gives each project its
own set of installed packages, separate from your system's global Python installation.

Common pip commands for beginners:


Once Python is installed (it comes with pip for version 3.4+), you can open your terminal
or command prompt and start using pip.

 Install a package:

pip install package_name

 Install a specific version of a package:

pip install package_name==1.2.3

 Upgrade a package to the latest version:

pip install --upgrade package_name

 Uninstall a package:

pip uninstall package_name

 List all installed packages:

pip list
 Save project dependencies: To create a requirements.txt file that lists all packages in
your current environment, which can be shared with others, use the freeze command.

pip freeze > requirements.txt

 Install packages from a requirements.txt file:

pip install -r requirements.txt


OOP Concepts in Python
Object Oriented Programming is a fundamental concept in Python, empowering
developers to build modular, maintainable and scalable applications.
OOPs is a way of organizing code that uses objects and classes to represent real-
world entities and their behavior. In OOPs, object has attributes thing that has specific
data and can perform certain actions using methods.
Python supports the core principles of object-oriented programming, which are the
building blocks for designing robust and reusable software. These are:
 Class
 Objects
 Polymorphism
 Encapsulation
 Inheritance
 Data Abstraction

Python Class:

A class is a collection of objects. Classes are blueprints for creating objects. A


class defines a set of attributes and methods that the created objects
(instances) can have.

Some points on Python class:

 Classes are created by keyword class.


 Attributes are the variables that belong to a class.
 Attributes are always public and can be accessed using the dot (.)
operator. Example: Myclass.Myattribute

Creating a Class
Here, class keyword indicates that we are creating a class followed by name
of the class (Dog in this case).

class Dog:
species = "Canine" # Class attribute

def __init__(self, name, age):


self.name = name # Instance attribute
self.age = age # Instance attribute

Explanation:
 class Dog: Defines a class named Dog.
 species: A class attribute shared by all instances of the class.
 __init__ method: Initializes the name and age attributes when a new
object is created.

Python Objects

An Object is an instance of a Class. It represents a specific implementation of


the class and holds its own data. An object consists of:
 State: It is represented by the attributes and reflects the properties of an
object.
 Behavior: It is represented by the methods of an object and reflects the
response of an object to other objects.
 Identity: It gives a unique name to an object and enables one object to
interact with other objects.

Advantages of OOP in Python:


 Modularity and Reusability:
Code is organized into self-contained units (classes and objects), promoting
reusability and reducing redundancy.
 Maintainability and Scalability:
The structured nature of OOP makes code easier to understand, modify, and extend,
especially in large and complex applications.
 Real-world Modeling:
OOP allows for a more intuitive and direct representation of real-world entities and
their relationships within the program.

Constructor and Overriding method in python:


A constructor is a special method in Python, named __init__ , used for initializing a
newly created object. Method overriding is an object-oriented programming feature that
allows a child class to provide a specific implementation of a method that is already
defined in its parent class.

Constructor ( __init__ )

A constructor is automatically called whenever a new instance of a class is created. Its


primary purpose is to set up the initial state of the object by assigning values to its
attributes.

Key characteristics
 The constructor method is always named __init__ (with double underscores).

 The first argument is always self , which is a reference to the newly created object
instance.

 It can take additional arguments to customize the object's initial attributes.

 Python does not support multiple constructors in the same way as languages like Java,
but you can simulate this functionality using default arguments.

Example

class Car:
# This is the constructor
def __init__(self, make, model):
self.make = make
self.model = model

def display_info(self):
print(f"Make: {self.make}, Model: {self.model}")

# Creating objects automatically calls the constructor


my_car = Car("Toyota", "Corolla")
my_car.display_info()

# Output: Make: Toyota, Model: Corolla


Method overriding
Method overriding allows a subclass to change or extend the behavior of a method it
inherits from a parent class. The method in the child class must have the same name
and the same number of parameters as the method in the parent class.

Key characteristics

 It requires an inheritance relationship between a parent (superclass) and a child


(subclass).

 The child class's method takes precedence over the parent's version when called on an
instance of the child class.

 You can call the parent's version of the method from within the overridden method using
the super() function.
Example

class Animal:
def speak(self):
print("The animal makes a sound.")

class Dog(Animal):
# Overrides the speak() method from the parent class
def speak(self):
print("The dog barks.")

class Cat(Animal):
# Overrides and extends the parent's speak() method
def speak(self):
super().speak() # Calls the parent method
print("The cat meows.")

# Create objects and call the overridden methods


animal = Animal()
animal.speak() # Output: The animal makes a sound.

dog = Dog()
dog.speak() # Output: The dog barks.

cat = Cat()
cat.speak() # Output:
# The animal makes a sound.
# The cat meows.

Overriding the constructor:


You can also override the __init__ constructor in a child class. This is often done when
the child class has additional attributes that need to be initialized. It is best practice to
call the parent's constructor using super() to ensure proper initialization of inherited
attributes.

Example

class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary

class Manager(Employee):
def __init__(self, name, salary, department):
# Calls the parent class's constructor to initialize name and salary
super().__init__(name, salary)
# Initializes the new attribute for the Manager class
self.department = department

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

# Create a Manager object


manager = Manager("Alice", 100000, "Marketing")
manager.display_details()

# Output: Name: Alice, Salary: 100000, Department: Marketing

Error & Exceptions:

In Python, both errors and exceptions disrupt the normal execution flow of a
program, but they differ in their nature and how they are typically handled.

Errors:
Errors represent fundamental problems in a program that prevent it from
running at all or indicate severe issues that cannot be easily recovered from
during runtime.
 Syntax Errors: These occur when the code violates Python's grammatical rules, such
as missing colons, incorrect indentation, or misspelled keywords. The Python interpreter
detects these before execution, preventing the program from starting.
Python
# Example of a Syntax Error
if True
print("Hello") # Missing colon after True

 Logical Errors (often leading to Exceptions): These are flaws in the program's logic
that cause it to produce incorrect results or behave unexpectedly. While not always
preventing execution, they can lead to situations that raise exceptions during runtime.
Exceptions:
Exceptions are events that occur during the execution of a program that
disrupt its normal flow. Unlike syntax errors, exceptions are typically detected
at runtime and can often be handled to prevent program termination.
 Runtime Errors:
Exceptions are a type of runtime error. They signal that something unexpected
happened during the program's execution, such as:
 ZeroDivisionError: Attempting to divide a number by zero.
 FileNotFoundError: Trying to access a file that does not exist.
 TypeError: Performing an operation on an object of an inappropriate type.
 IndexError: Accessing an index outside the bounds of a sequence (e.g., list, tuple).

 Handling Exceptions:

Python provides the try-except block for handling exceptions.


 The try block contains the code that might raise an exception.

 The except block specifies how to handle a particular exception if it occurs within
the try block.
 else and finally blocks can also be used for additional control flow in exception handling.

# Example of Exception Handling


try:
result = 10 / 0
except ZeroDivisionError:
print("Error: Cannot divide by zero!")
finally:
print("This will always execute.")

 Raising Exceptions: Programmers can also explicitly raise exceptions using


the raise keyword to signal specific error conditions within their code.

def validate_age(age):
if age < 0:
raise ValueError("Age cannot be negative.")
return age

In essence, while errors represent fundamental structural or logical flaws,


exceptions are runtime events that can often be anticipated and managed to
maintain program stability.

Difference between Error & Exception:


Aspect Error Exception

Occurrence Errors are fundamental issues that prevent a Exceptions are events that interrupt the normal flow
program from even starting its execution. They of the program during runtime (execution).
occur during the parsing stage, also known as
compile-time.

Severity Errors are generally more severe and often indicate Exceptions are less severe and represent
a problem that cannot be recovered from gracefully conditions that a program can anticipate and handle
by the program itself. to continue running.

Handling Errors, particularly syntax errors, cannot be caught Exceptions can be caught and managed
and handled by try...except blocks. They must be using try...except blocks, allowing the program
fixed in the code before it can be run. to handle the issue and prevent a crash.

Common SyntaxError: Caused by code that does not follow ZeroDivisionError: Raised when a number is
types the correct Python syntax, such as missing colons divided by zero.
or parentheses. NameError: Raised when a variable or function
IndentationError: Occurs due to incorrect or name is used but has not been defined.
inconsistent indentation, which is a key part of TypeError: Occurs when an operation is performed
Python's syntax. on an object of an inappropriate type, e.g., adding a
number and a string.
FileNotFoundError: Raised when the program
attempts to open a file that does not exist.

Resolution Errors require the programmer to fix the underlying Exceptions are typically handled with code logic,
structural problem in the source code. providing an alternative path for the program to
follow when an unusual event occurs.

Example if True (missing a colon) will cause 10 / 0 will raise a ZeroDivisionError at runtime.
a SyntaxError and stop the program from running. A try...except block can catch this and print a
user-friendly message instead of crashing.

Multithreading & GUI Programming in python:


Using multithreading with Python's graphical user interface (GUI) frameworks is
essential for creating responsive applications. The main thread, which runs the GUI's
event loop, becomes unresponsive if blocked by a long-running task. Multithreading
offloads these tasks to a separate worker thread, allowing the GUI to remain
interactive. The primary challenge is to ensure "thread safety"—safely updating GUI
elements from a different thread.

Multithreading basics in Python:


Python's built-in threading module is the standard way to implement multithreading.

The Global Interpreter Lock (GIL):

 Python's GIL ensures that only one thread can execute Python bytecode at a time,
limiting true parallelism on multi-core systems.

 The GIL is not a limitation for I/O-bound tasks (like reading a file or network requests)
because the GIL is released while a thread waits for I/O operations to complete. This
allows other threads to run concurrently.

 For CPU-bound tasks (like complex calculations), you should use


the multiprocessing module instead, which bypasses the GIL by using separate
processes.

Core threading components:

 Thread class: The main object for creating and managing threads. You pass the target
function and its arguments to its constructor.

 .start() : Begins the thread's execution.

 .join() : Blocks the main program until the specified thread completes. This is useful for
waiting on a background task to finish before exiting.

 Lock : A synchronization primitive that prevents race conditions by allowing only one
thread at a time to access a shared resource. Use with lock: to safely manage the
acquisition and release of the lock.

 Queue : The queue module provides a thread-safe queue that is ideal for safely passing
data between threads.

Concept of testing turtle graphics in python:


Testing Turtle Graphics in Python primarily involves
verifying the internal state and logic of your code, rather than visually inspecting the
output. Since turtle is a graphical library, direct automated visual comparisons can be
complex. The most effective approach is to separate the drawing logic from the
functions that manipulate the turtle's state, and then use a mocking framework to test
the logic.

Key concepts for testing Turtle graphics:


1. Separate logic from presentation

Treat your program's core logic as distinct from the turtle library's graphical output. Your
testing should focus on whether your functions correctly calculate coordinates, angles,
and other states, not on what the final drawing looks like.

Example:
Instead of a single function draw_square() , split the responsibilities:

 A function get_square_moves(size) that returns a list of coordinates and turns.

 A separate draw_shape() function that takes this list and executes the turtle commands.

This makes get_square_moves() easy to test with standard unit testing tools.

2. Use mocking to isolate the turtle library

Mocking is the practice of replacing objects in your tests with "mock" objects that mimic
their behavior. This is crucial for turtle because you do not want to launch a graphics
window every time you run a test. The unittest.mock module (or the pytest-mock plugin
for pytest ) is the standard tool for this. The core idea is to replace
the turtle.Turtle and turtle.Screen objects with mocks and then check if the correct
methods were called with the expected arguments.

Common mocks to apply:

 mock_turtle.forward()

 mock_turtle.right()

 mock_turtle.penup() and mock_turtle.pendown()

 mock_screen.listen() and mock_screen.onkeypress()

You can assert that mock_turtle.forward.assert_called_with(100) was executed, confirming


your function's logic.

3. Test interactions with the turtle.Screen

For interactive games or applications, your code often binds functions to keyboard
presses using screen.onkeypress() . You can test this behavior by mocking
the turtle.Screen and confirming that the correct functions are bound to the events.

Example test for keyboard events:


1. Mock the turtle.Screen instance.

2. Run the function that sets up your key bindings.

3. Simulate a keypress event by calling the function that onkeypress would normally
invoke.

4. Assert that your turtle's state (e.g., coordinates) has changed as expected.

4. Advanced visual testing with screenshot comparison

For complex graphical outputs where the final visual result is important, you can perform
visual regression testing.

How it works:
1. Capture baseline: On the first run, your test captures a screenshot of the turtle window
and saves it as the "baseline." Libraries like PyAutoGUI can automate this process.

2. Compare images: On subsequent test runs, a new screenshot is captured and


compared to the baseline.

3. Detect differences: An image processing library (like Pillow or ImageChops ) compares


the images pixel by pixel to identify visual regressions.

This approach is more complex to set up and maintain due to minor visual differences
between platforms, but it offers the most comprehensive way to test the final visual
output.

Unit testing:
Unit testing is a software development practice in which individual components of an
application are tested to ensure they work as intended. In Python, developers can use
frameworks like the built-in unittest or the popular third-party pytest to write, organize,
and run these tests.

Key Python testing frameworks


unittest

unittest is Python's built-in, standard library testing framework. It uses an object-oriented


approach inspired by the JUnit framework in Java.
 Structure: Tests are organized into classes that inherit from unittest.TestCase . Each test
function within the class must begin with test_ to be discovered automatically.

 Assertions: The framework provides a rich set of built-in methods for verifying
conditions, such as assertEqual() , assertTrue() , and assertRaises() .

 Fixtures: It supports setup and teardown methods ( setUp() and tearDown() ) for
preparing and cleaning up the testing environment for each test.

 Best for: Developers who prefer a classic, object-oriented testing style or for projects
where external dependencies are not desired.

pytest

pytest is a widely-used third-party framework known for its simple, flexible, and concise
syntax.

 Structure: Tests can be written as simple functions, without needing to be part of a


class. Test files should be named test_*.py or *_test.py , and test functions must start
with test_ .

 Assertions: It uses Python's standard assert keyword, which is less verbose and
easier to read than unittest 's assertion methods.

 Fixtures: It has a powerful and flexible fixture system that simplifies the setup and
teardown process. Fixtures can be shared across multiple test files.

 Best for: Most Python projects, from small to large, due to its minimal boilerplate and
rich plugin ecosystem.

Example of writing a unit test:


This example demonstrates how to write unit tests for a simple calculator application
using both unittest and pytest .

1.Create the application code

First, create a file named calculator.py with the following code:

class Calculator:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b

def divide(self, a, b):


if b == 0:
raise ValueError("Cannot divide by zero")
return a / b

2. Write tests using unittest


Next, create a file named test_calculator_unittest.py with the following test suite:

import unittest
from calculator import Calculator

class TestCalculator(unittest.TestCase):
def setUp(self):
# Set up a new Calculator instance before each test
self.calc = Calculator()

def test_add(self):
self.assertEqual(self.calc.add(2, 3), 5)
self.assertEqual(self.calc.add(-1, 1), 0)

def test_subtract(self):
self.assertEqual(self.calc.subtract(5, 2), 3)
self.assertEqual(self.calc.subtract(10, 20), -10)

def test_divide_by_zero(self):
with self.assertRaises(ValueError):
self.calc.divide(10, 0)

if __name__ == '__main__':
unittest.main()

3. Run the unittest tests


Execute the tests from your terminal by running the script:

python -m unittest test_calculator_unittest.py


4. Write tests using pytest
Create a new file named test_calculator_pytest.py for the pytest version of the tests:

import pytest
from calculator import Calculator

def test_add():
calc = Calculator()
assert calc.add(2, 3) == 5
assert calc.add(-1, 1) == 0

def test_subtract():
calc = Calculator()
assert calc.subtract(5, 2) == 3
assert calc.subtract(10, 20) == -10

def test_divide_by_zero():
calc = Calculator()
with pytest.raises(ValueError):
calc.divide(10, 0)
.

4. Run the pytest tests


Run the tests with the pytest command in your terminal (you may need to install
it first with pip install pytest ):

Best practices for unit testing in Python:


 Arrange, Act, Assert (AAA): Structure your tests into three clear phases: Arrange (set up
objects and data), Act (call the code being tested), and Assert (verify the outcome).

 Use descriptive names: Choose clear and meaningful names for your test functions and
classes, such as test_add_two_positive_numbers() .

 Isolate tests: Each test should be independent and not rely on the outcome or state of
other tests. Use test fixtures ( setUp in unittest or pytest fixtures) to create a clean state.

 Test for edge cases: Go beyond typical inputs and include boundary conditions, invalid
data, and potential error cases to ensure robustness.
 Aim for high coverage: Use a coverage tool like coverage.py to identify untested parts of
your codebase, but don't blindly aim for 100% coverage.

 Avoid complex logic in tests: Tests should be simple and straightforward. If your test
logic becomes too complicated, it may indicate a problem with the code being tested

You might also like