0% found this document useful (0 votes)
8 views122 pages

Introduction to Computer Systems and Programming_Com1201

The document is a syllabus for an introductory course on computer systems and programming at Port Said University, prepared for first-level students. It covers various topics including programming languages, algorithms, conditional statements, loops, and arrays, with practical labs and exercises included. The course aims to provide foundational knowledge in computer programming and its applications.

Uploaded by

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

Introduction to Computer Systems and Programming_Com1201

The document is a syllabus for an introductory course on computer systems and programming at Port Said University, prepared for first-level students. It covers various topics including programming languages, algorithms, conditional statements, loops, and arrays, with practical labs and exercises included. The course aims to provide foundational knowledge in computer programming and its applications.

Uploaded by

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

Port Said University Faculty of Science Department of

Math. & Comp. Sci.

Introduction to
Computer Systems and
Programming
Com1201
For First Level
General

Prepared by
DR. MOSTAFA HERAJY
DR. DOAA EL-MORSHEDY

2024-2025
Contents

Lecture 1: Introduction to Programming 7


Computer Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Applications of Computer Programming . . . . . . . . . . . . . . . . . . 8
Compilers and IDEs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Key Functions of a Compiler . . . . . . . . . . . . . . . . . . . . . . . . . 9
Integrated Development Environment (IDE) . . . . . . . . . . . . . . . . 10
Types of Prorgamming Langaues . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Based on Abstraction Level . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Based on Execution Method . . . . . . . . . . . . . . . . . . . . . . . . . 11
Based on Programming Paradigm . . . . . . . . . . . . . . . . . . . . . . 11
Based on Specific Application Domains (Domain-Specific Languages) . . 12
Example of Programming Languages . . . . . . . . . . . . . . . . . . . . . . . . 13
The C Programming Language . . . . . . . . . . . . . . . . . . . . . . . . 13
Python: A High-Level, Versatile Language . . . . . . . . . . . . . . . . . . 14
Java: The Cross-Platform Workhorse . . . . . . . . . . . . . . . . . . . . . 14
C++: Combining Performance with Abstraction . . . . . . . . . . . . . . . 15
JavaScript: The Language of the Web . . . . . . . . . . . . . . . . . . . . 15
Algorithms and Flowcharts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Types of Programming Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Syntax Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Logical Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Runtime Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

Lecture 2: Hello World 23


Programming using Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Setting Up Your Python Environment . . . . . . . . . . . . . . . . . . . . . . . 25
Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
How to Run the Program . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
A Simple Calculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Block Indentation In Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Practice Lab: Writing and Running a Simple Python Program . . . . . . . . . . 34
2 CO N TENTS

Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

Lecture 3: Conditional Statements: Making Decisions 37


Types of Conditional Statements in Python . . . . . . . . . . . . . . . . . . . . 37
If Statement(Single Condition Check) . . . . . . . . . . . . . . . . . . . . . . . 37
Syntax Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Example 1: Checking if a Number is Positive . . . . . . . . . . . . . . . . . . . 37
Example 2: Checking for Even Numbers . . . . . . . . . . . . . . . . . . . . . . 38
Example 3: Checking if a Person is an Adult . . . . . . . . . . . . . . . . . . . . 38
if-else Statement (Two Conditions - True or False) . . . . . . . . . . . . . . . . 38
if-elif-else Statement (Multiple Conditions) . . . . . . . . . . . . . . . . . . . . 40
Nested if Statements (if Inside Another if) . . . . . . . . . . . . . . . . . . . . . 42
Using Logical Operators (and, or, not) . . . . . . . . . . . . . . . . . . . . . . . 44
Real-World Applications of Conditional Statements . . . . . . . . . . . . . . . 45
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Practice Lab: Writing and Running about if satatements in Python Program . . 46
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

Lecture 4: Loops: Repeating Tasks 51


Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
for Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Example 1: Using for Loop with a List . . . . . . . . . . . . . . . . . . . . . . . 51
Example 2: Using for Loop with range() . . . . . . . . . . . . . . . . . . . . . . 52
Example 3: Iterating Over a String . . . . . . . . . . . . . . . . . . . . . . . . . 52
Example 4: Using for Loop with range() and step . . . . . . . . . . . . . . . . . 52
Example 5: Using for Loop with break and continue . . . . . . . . . . . . . . . 53
Nested for Loops (Loop Inside a Loop) . . . . . . . . . . . . . . . . . . . . . . . 53
Example1: Multiplication Table . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Using else with for Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
else in for Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
else with break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
While Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Example 1: Using while Loop to Print Numbers . . . . . . . . . . . . . . . . . . 55
Example 2: Using while Loop with break . . . . . . . . . . . . . . . . . . . . . . 56
Example 3:Using while Loop with continue . . . . . . . . . . . . . . . . . . . . 56
Example 4: Using while Loop with else . . . . . . . . . . . . . . . . . . . . . . 56
Example 4:Nested while Loops (Multiplication Table) . . . . . . . . . . . . . . 57
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Practice Lab:Understanding Loops in Python . . . . . . . . . . . . . . . . . . . 58
Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Lab Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Step 1: Using a for Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Step 2: Using a while Loop . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Step 3: Test Your Program . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Step 4: Writing a Loop-Based Program (Challenge) . . . . . . . . . . . . . 59
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Lecture 5: Arrays: Indexing Variables 61


Introdution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Difference Between Lists and Arrays . . . . . . . . . . . . . . . . . . . . . . . . 61
3.Creating an Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4.Accessing Elements in an Array (Indexing) . . . . . . . . . . . . . . . . . . . 62
Modifying an Array (Changing Values) . . . . . . . . . . . . . . . . . . . . . . . 62
5.Adding and Removing Elements . . . . . . . . . . . . . . . . . . . . . . . . . 63
Slicing Arrays (Extracting Portions) . . . . . . . . . . . . . . . . . . . . . . . . . 63
Looping Through an Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Finding the Length of an Array . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Sorting an Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Practice Lab: Writing and Running about if satatements in Python Program . . 68
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

Lecture 6: Functions: Better Organize Your Code 71


Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Advantages of Using Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Defining and Calling a Function . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Function with Parameters (Passing Arguments) . . . . . . . . . . . . . . . . . . 72
Function with Multiple Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 72
Function with Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
6.Function with Keyword Arguments (kwargs) . . . . . . . . . . . . . . . . . . 73
Arbitrary Arguments (*args and **kwargs) . . . . . . . . . . . . . . . . . . . . . 74
Recursive Functions (Function Calling Itself) . . . . . . . . . . . . . . . . . . . 74
9.Lambda Functions (Anonymous Functions) . . . . . . . . . . . . . . . . . . . 75
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Practice Lab: Writing and Running about if satatements in Python Program . . 75
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Lecture 7: External Packages and Modules 79


Purpose of Python Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Examples of Using Python Packages . . . . . . . . . . . . . . . . . . . . . . . . 80
pip: The Python Package Installer . . . . . . . . . . . . . . . . . . . . . . . . . 81
Example of Popular Python Packages . . . . . . . . . . . . . . . . . . . . . . . 82
NumPy: Numerical Computing Made Efficient . . . . . . . . . . . . . . . 82
Pandas: Data Analysis and Manipulation . . . . . . . . . . . . . . . . . . 83
Matplotlib: Visualizing Data . . . . . . . . . . . . . . . . . . . . . . . . . 84
Requests: Simplifying HTTP Requests . . . . . . . . . . . . . . . . . . . . 85
Web Development Frameworks: Django and Flask . . . . . . . . . . . . . 86
Creating Your Own Package in Python . . . . . . . . . . . . . . . . . . . . 86
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Practice Lab: Creating and Using Python Packages . . . . . . . . . . . . . . . . 90
Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
4 CO N TENTS

Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Part 1: Setting Up the Package Structure . . . . . . . . . . . . . . . . . . . 91
Part 2: Writing the Package Modules . . . . . . . . . . . . . . . . . . . . . 92
Part 3: Testing Your Package . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Part 4: Using Your Package in a Script . . . . . . . . . . . . . . . . . . . . 93
Part 5: Reflection and Exploration . . . . . . . . . . . . . . . . . . . . . . 93
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

Lecture 8: Files and Streams: Saving and Loading Data 95


Understanding Files in Python . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
File Paths and Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Basic File Handling Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Working with Binary Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Streams in Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Advanced File and Stream Operations . . . . . . . . . . . . . . . . . . . . . . . 98
Real-World Examples and Use Cases . . . . . . . . . . . . . . . . . . . . . . . . 99
Log File Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Data Analysis with CSV Files . . . . . . . . . . . . . . . . . . . . . . . . . 99
Streaming Data in Web Applications . . . . . . . . . . . . . . . . . . . . . 100
Best Practices for File and Stream Handling . . . . . . . . . . . . . . . . . . . . 100
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Practice Lab: Files and Streams in Python . . . . . . . . . . . . . . . . . . . . . 101
Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Part 1: Basic File Operations . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Part 2: Appending to Files and Error Handling . . . . . . . . . . . . . . . 103
Part 5: Reflection and Exploration . . . . . . . . . . . . . . . . . . . . . . 103
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

Lecture 9: Classes and Objects: Object Oriented Programming 105


Introduction to Object-Oriented Programming . . . . . . . . . . . . . . . . . . 105
Basic Concepts in OOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Why Use Object-Oriented Programming? . . . . . . . . . . . . . . . . . . 106
Creating Classes and Objects in Python . . . . . . . . . . . . . . . . . . . . . . 106
Creating Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Understanding the __init__ Method and Instance Attributes . . . . . . . . . . 107
Inheritance, Encapsulation, and Polymorphism in Python . . . . . . . . . . . . 107
Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Polymorphism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Special (Magic/Dunder) Methods and Operator Overloading . . . . . . . . . . 109
Common Special Methods . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Class Methods, Static Methods, and Properties . . . . . . . . . . . . . . . . . . 110
Class Methods: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Static Methods: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Properties: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Best Practices and Common Pitfalls in Python OOP . . . . . . . . . . . . . . . 112
Real-World Applications and Conclusion . . . . . . . . . . . . . . . . . . . . . 112
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Practice Lab: Object-Oriented Programming in Python . . . . . . . . . . . . . 113
Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Part 1: Creating a Basic Class and Instantiating Objects . . . . . . . . . . 114
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

Lecture 10: Beyond the Basics: Please Help Yourself 117


Master the Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Understand Python Syntax and Basics . . . . . . . . . . . . . . . . . . . . 117
Practice with Exercises and Small Projects . . . . . . . . . . . . . . . . . . 117
Develop Good Coding Habits . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Read and Understand Others’ Code . . . . . . . . . . . . . . . . . . . . . 118
Follow Python Style Guides . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Learn to Debug and Test Your Code . . . . . . . . . . . . . . . . . . . . . 118
Engage with the Python Community . . . . . . . . . . . . . . . . . . . . . . . . 119
Participate in Online Forums and Groups . . . . . . . . . . . . . . . . . . 119
Contribute to Open-Source Projects . . . . . . . . . . . . . . . . . . . . . 119
Create a Personal Portfolio . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Explore Advanced Topics Gradually . . . . . . . . . . . . . . . . . . . . . . . . 120
Deepen Your Knowledge Over Time . . . . . . . . . . . . . . . . . . . . . 120
Stay Updated and Keep Learning . . . . . . . . . . . . . . . . . . . . . . . 120
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
6 CO N TENTS
Lecture 1: Introduction to Programming

Computer Programming
Computer programming is the process of designing and writing instructions that a com-
puter follows to perform specific tasks. It involves creating code using programming
languages (like Python, Java, or C++) to develop software applications, automate tasks,
solve problems, or control hardware. The process typically includes planning algorithms,
writing and testing code, debugging errors, and maintaining the program over time. Es-
sentially, programming is the art and science of translating human ideas into a language
that computers can understand and execute.
At its core, programming involves several key steps:

1. Problem Analysis and Algorithm Design: Before any code is written, program-
mers analyze the problem at hand to understand what needs to be accomplished.
This phase often involves breaking down a complex problem into smaller, more
manageable parts and designing an algorithm—a step-by-step procedure or set
of rules—to solve each part. Algorithms can be represented in pseudocode or
flowcharts, which help visualize the logic before actual implementation.

2. Writing Code with a Programming Language: Once the algorithm is defined, the
next step is to translate it into a programming language. There are many program-
ming languages available (such as Python, Java, C++, JavaScript, and many others),
each with its own syntax, strengths, and use cases. High-level languages are closer
to human language and abstract away many of the hardware details, making them
easier to write and maintain. Some languages, however, may be closer to machine
language, offering greater control over hardware but often at the cost of increased
complexity.

3. Compilation and Interpretation Depending on the language, the written code is


either compiled or interpreted.
Compiled languages (like C or C++) convert the entire source code into machine
code through a compiler before execution. This often leads to faster execution
times once compiled. Interpreted languages (like Python or JavaScript) are exe-
cuted line by line by an interpreter, which can make debugging easier and the
development process more flexible, though sometimes at the expense of perfor-
mance.

4. Testing and Debugging:


Once the code is written, it must be tested to ensure it works correctly. Testing
can range from simple unit tests (which check individual parts of the code) to
8 L E C T URE 1: INTRODUCTION TO PROGRAMMING

more comprehensive system tests that verify the software’s behavior as a whole.
Debugging is the process of identifying, isolating, and fixing errors or “bugs” that
occur during execution. This iterative process is essential for refining the code and
improving its reliability and performance.

5. Maintenance and Improvement: After a program is deployed, it often needs up-


dates and improvements. Maintenance may involve adding new features, optimiz-
ing performance, or fixing issues that were not caught during the initial testing
phases. This stage ensures that the software remains useful and secure over time.

Applications of Computer Programming


Computer programming is a versatile field that underpins many modern technologies
and industries. Here are some key applications:

1. Web Development: Programming is used to create dynamic websites and web


applications. Languages like JavaScript, Python, Ruby, and PHP enable developers
to build everything from simple blogs to complex e-commerce platforms and social
networks.

2. Mobile Applications: Mobile app development relies on programming languages


such as Swift, Kotlin, Java, and Dart to create apps for platforms like iOS and
Android, ranging from utility apps to sophisticated games and productivity tools.

3. Desktop Software: Computer programming is essential for developing operating


systems, productivity software, multimedia applications, and other programs that
run on personal computers and workstations using languages like C++, C#, and
Java.

4. Game Development: Video game development leverages programming for both


game logic and graphics rendering. Languages like C++, C#, and scripting lan-
guages in game engines (e.g., Unity, Unreal Engine) are commonly used.

5. Embedded Systems and Internet of Things (IoT): Programming plays a critical


role in developing software for embedded devices, which are found in household
appliances, automobiles, industrial machines, and smart devices connected to the
IoT.

6. Scientific Computing and Data Analysis: Researchers use programming languages


such as Python, R, and MATLAB to perform complex data analysis, simulations,
and computational modeling in fields like physics, biology, and finance.

7. Artificial Intelligence (AI) and Machine Learning (ML): AI and ML applications,


including natural language processing, computer vision, and predictive analytics,
rely heavily on programming to implement algorithms and manage large datasets.

8. Automation and Scripting: Programming is used to write scripts that automate


repetitive tasks, manage system operations, and streamline business processes,
enhancing productivity across many sectors.
9. Cybersecurity: Developers create tools for encryption, intrusion detection, and
secure communications. Programming also supports the development of protocols
and applications that safeguard data and systems.

10. Network and Cloud Computing: Programming is fundamental for developing


network protocols, managing distributed systems, and building cloud-based appli-
cations and services that scale with demand.

11. Virtual Reality (VR) and Augmented Reality (AR): These emerging technologies rely
on programming to create immersive environments and applications for enter-
tainment, education, training, and simulation.

12. Blockchain and Cryptocurrency: Programming is used to build decentralized ap-


plications (dApps), smart contracts, and blockchain protocols that underpin cryp-
tocurrencies and other distributed ledger technologies.

Compilers and IDEs


A compiler is a specialized program that translates code written in a high-level program-
ming language (such as C, C++, or Java) into a lower-level language, often machine code
(binary) or an intermediate language, that a computer’s hardware can execute directly.
This translation process is crucial because computers understand only machine-level
instructions. Here’s a detailed look at what compilers do and their role in programming:

Key Functions of a Compiler


1. Translation of Code: The primary role of a compiler is to convert source code
(human-readable code) into machine code. This process allows the computer
to execute the program. By translating the code, the compiler bridges the gap
between the programmer’s high-level abstractions and the computer’s low-level
hardware instructions.

2. Error Detection and Reporting: During the translation process, the compiler checks
the source code for syntactic and semantic errors.

3. Optimization: Compilers often perform various optimizations to improve the


performance of the generated machine code. This may include: Code optimization:
Streamlining the code to run faster or use fewer resources. Memory optimization:
Reducing memory consumption through techniques like inlining functions or
eliminating redundant computations. These optimizations help in producing
efficient executables that run well on the target hardware.

4. Code Generation: After analyzing and optimizing the source code, the compiler
generates machine code or an intermediate representation (such as bytecode in
Java) that can be executed by the computer or a virtual machine. This stage in-
volves translating abstract instructions into specific instructions that the processor
understands.
10 L E C T URE 1: INTRODUCTION TO PROGRAMMING

5. Linking Although often considered a separate step handled by a linker, many


compilers work in conjunction with linkers to combine multiple code modules (or
libraries) into a single executable program. The linking process resolves references
between modules and ensures that all parts of the program are correctly connected.

In summary, compilers are essential tools in programming that facilitate the transfor-
mation of human-readable source code into efficient, executable machine code. They
play a critical role in ensuring that programs run correctly and efficiently while providing
a level of abstraction that makes software development more accessible and productive.

Integrated Development Environment (IDE)


An IDE is a comprehensive software application that provides a unified interface to
support software development. It integrates various tools needed for coding, debugging,
testing, and managing software projects.
Components and Features:

• Code Editor: A text editor with features like syntax highlighting, auto-completion,
and code formatting.
• Compiler/Interpreter Integration: While an IDE usually includes a compiler (or
interfaces with one), it also provides additional functionality to manage and run
the code.
• Debugger: Tools to step through code, inspect variables, and diagnose issues.
• Build Automation: Features that help manage the process of compiling, linking,
and packaging the software.
• Version Control Integration: Tools to work with systems like Git for code manage-
ment and collaboration.

IDEs offer a user-friendly, graphical environment that simplifies the coding process,
making it easier for developers to write, test, and debug code in one place. They are
designed to streamline the entire development cycle.
while a compiler is crucial for transforming high-level code into machine-executable
instructions, an IDE offers a complete environment that not only includes a compiler
but also provides various tools to facilitate the entire software development process.

Types of Prorgamming Langaues


Programming languages can be classified in several ways, and each classification offers
insight into how languages are designed and used.
the landscape of programming languages is vast and multifaceted. The various
classifications—whether by abstraction level, execution method, programming paradigm,
application domain, or type system—highlight the diversity and specialization within the
field. Understanding these distinctions can help developers choose the right language
for the task at hand and better appreciate the design decisions behind each language.
Here’s a more detailed breakdown of the different types of programming languages:
Based on Abstraction Level
• Low-Level Languages Machine Language: The most basic level of programming,
consisting entirely of binary code (0s and 1s) that the computer’s processor can
execute directly. Characteristics: Hardware-specific, Very fast execution, and Diffi-
cult to write and maintain. Example Use: Writing firmware or performance-critical
routines in embedded systems.
Assembly Language: A symbolic representation of machine language that uses
mnemonic codes (like MOV, ADD, or JMP) instead of binary, making it slightly
easier to read and write. Characteristics: Still hardware-specific, Requires an assem-
bler to translate into machine code and Offers fine-grained control over hardware
Example Use: System programming, device drivers, or real-time applications.
• High-Level Languages Languages that provide a greater abstraction from machine
details, allowing programmers to write instructions in a more human-readable
form. Characteristics: Easier to learn and use, Portable across different systems (to
some degree), Provide extensive libraries and frameworks.

Based on Execution Method


• Compiled Languages: Languages where source code is translated entirely into ma-
chine code by a compiler before execution. Characteristics: Performance: Typically
produce fast executables due to direct translation to machine code. Error Checking:
Compile-time error detection can catch many issues before execution. Deploy-
ment: Usually distributed as standalone executables. Examples: C/C++: Known
for performance-critical applications and system programming. Go: Designed for
efficiency and concurrency.
• Interpreted Languages: Languages where code is executed on the fly by an in-
terpreter, which reads and executes the source code line by line. Characteristics:
Flexibility: Easier to test and debug since you can run code snippets interactively.
Performance: Generally slower than compiled languages due to the overhead of
interpretation at runtime. Examples: Python: Widely used in data science, web
development, and automation. Ruby: Known for its elegant syntax and web devel-
opment frameworks like Ruby on Rails.
• Hybrid Approaches Some languages use a two-step process where the source code
is first compiled into an intermediate form (like bytecode) and then executed by a
virtual machine or interpreter. Characteristics: Portability: The intermediate code
can run on any platform that has the appropriate virtual machine. Balance: Offers
some performance benefits while retaining platform independence. Examples:
Java: Compiled into bytecode, then run on the Java Virtual Machine (JVM). C#:
Uses the Common Intermediate Language (CIL) and runs on the .NET framework.

Based on Programming Paradigm


• Procedural Programming: Centers on a sequence of well-structured procedures or
routines (functions) to perform tasks. Characteristics: Emphasizes a clear sequence
12 L E C T URE 1: INTRODUCTION TO PROGRAMMING

of steps and subroutines. Easy to understand for tasks that follow a linear sequence.
Examples: C: Widely used for system and application software. Pascal: Often used
in academic settings for teaching programming concepts.

• Object-Oriented Programming (OOP) Organizes software design around data, or


objects, and the methods that operate on those objects. Characteristics: Promotes
modularity, code reuse, and abstraction. Uses concepts like classes, inheritance,
encapsulation, and polymorphism.
Examples: Java: One of the most popular OOP languages for enterprise applications.
C++: Combines OOP with procedural programming features.

• Functional Programming: Emphasizes the use of mathematical functions and


avoids changing state or mutable data. Characteristics: Promotes immutability
and first-class functions. Often leads to more predictable and easier-to-test code.
Examples: Haskell: Purely functional with a strong static type system. Erlang:
Designed for highly concurrent and fault-tolerant systems.

• Logic Programming Based on formal logic, programs are written as sets of sen-
tences in logical form, expressing facts and rules about some problem domain.
Characteristics: Computation is performed through logical inference. Well-suited
for problems involving complex relationships and rules. Examples: Prolog: Used
in artificial intelligence and computational linguistics.

• Scripting Languages: Often designed for automating tasks, these languages tend
to be easy to write and integrate with other systems. Characteristics: Interpreted
and dynamically typed. Excellent for writing short programs (scripts) to automate
repetitive tasks. Examples: JavaScript: Dominant in web development for client-
side interactivity. PHP: Widely used for server-side web development.

• Multi-Paradigm Languages Languages that support more than one programming


paradigm, allowing developers to choose the best approach for a given problem.
Characteristics: Flexibility in design and implementation. Can handle different
types of problems by combining paradigms. Examples: Python: Supports pro-
cedural, object-oriented, and functional programming styles. C++: Allows both
object-oriented and procedural programming.

Based on Specific Application Domains (Domain-Specific Languages)


• Web Development Languages: tailored for creating and managing content on the
web. Characteristics: Often include markup and styling capabilities. May integrate
with scripting languages for interactivity. Examples: HTML/CSS: Fundamental for
web page structure and styling. JavaScript: Essential for client-side behavior on
web pages.

• Database Query Languages: Designed for managing and querying databases. Char-
acteristics: Focus on data retrieval, manipulation, and management. Often declar-
ative, meaning you specify what data you want rather than how to retrieve it.
Examples: SQL (Structured Query Language): The standard language for relational
database management systems.

• Scientific and Statistical Computing Languages: Optimized for data analysis, nu-
merical computations, and statistical modeling. Characteristics: Include extensive
libraries for mathematical functions, data visualization, and statistical operations.
Often used in research, academia, and data-intensive industries. Examples: R:
Popular in statistics and data analysis. MATLAB: Widely used in engineering and
scientific research.

Example of Programming Languages


Over the decades, a wide array of programming languages has emerged, each with unique
design philosophies, syntax, and use cases. From low-level languages that offer precise
control over hardware to high-level languages that emphasize developer productivity
and ease of use, the diversity of programming languages reflects the multifaceted nature
of computer science. In this article, we will explore examples of several influential
programming languages—namely C, Python, Java, C++, and JavaScript—highlighting
their history, core characteristics, and typical domains of application.

The C Programming Language


Developed in the early 1970s, the C programming language has been one of the most
influential languages in the history of computing. C was designed with the goal of
providing low-level access to memory and efficient mapping to machine instructions,
while still offering the abstraction needed to write portable code. Its design strikes
a balance between the precision of assembly language and the clarity of high-level
languages.
C is celebrated for its efficiency. By offering low-level memory manipulation through
pointers and direct access to hardware resources, C allows developers to write programs
that execute with minimal overhead. This feature makes C an ideal choice for system-
level programming, embedded systems, and operating system development.
Although C programs often require careful management of system resources, the
language itself was designed to be portable across various hardware platforms. The C
standard library provides a consistent set of functions that abstract away some of the
platform-specific details, making it easier to compile C programs on different systems.
The language offers a relatively small set of keywords and a straightforward syntax,
giving programmers fine-grained control over both the behavior and performance of
their applications. However, this simplicity comes at the cost of requiring developers to
manage memory manually, which can lead to errors if not handled carefully.
C remains the language of choice for many areas, including operating system kernels
(like Linux), embedded systems, and performance-critical applications. Its influence is
so pervasive that many modern languages—such as C++, Java, and even Python in its
C-implemented core—draw heavily from C’s design principles.
14 L E C T URE 1: INTRODUCTION TO PROGRAMMING

Python: A High-Level, Versatile Language


Python was first released in 1991. Designed with readability and simplicity in mind,
Python emphasizes code clarity and ease of maintenance. It is a high-level, interpreted
language that supports multiple programming paradigms, including procedural, object-
oriented, and functional programming.
Python’s syntax is often described as “executable pseudocode.” Its clean, straightfor-
ward structure reduces the cognitive load on developers, making it an excellent language
for beginners as well as for rapid prototyping.
Being dynamically typed, Python allows variables to be used without explicit type dec-
larations. This flexibility speeds up development and enables rapid iteration. However,
it also means that type-related errors may only be caught at runtime.
Python boasts a vast standard library and a wealth of third-party modules available
through repositories like PyPI. Whether for web development (using frameworks like
Django or Flask), data science (with libraries like NumPy, Pandas, and SciPy), or machine
learning (with TensorFlow or scikit-learn), Python’s extensive ecosystem supports a wide
range of applications.
Python is employed across a myriad of domains. In data science and machine learn-
ing, Python’s simplicity and the strength of its libraries make it the language of choice for
researchers and practitioners alike. It is also widely used in web development, automa-
tion, and scientific computing. Its role in education further underscores its importance
as a language that balances power with simplicity.

Java: The Cross-Platform Workhorse


Introduced by Sun Microsystems in 1995, Java was designed with the goal of allowing
developers to write once, run anywhere. Java’s philosophy centers on portability and
platform independence, largely achieved through the use of the Java Virtual Machine
(JVM). Programs written in Java are compiled into an intermediate bytecode, which
the JVM interprets, ensuring that Java applications can run on any device that has a
compatible JVM.
Java is inherently object-oriented, with a strong emphasis on encapsulation, inheri-
tance, and polymorphism. This design promotes code reuse and modularity, which is
critical for large-scale software systems.
Java’s standard library is extensive, offering built-in support for data structures, net-
working, concurrency, and more. This robustness enables developers to implement
complex functionalities without needing to build every component from scratch.
The JVM provides a sandbox environment that improves security by isolating Java
applications from the underlying hardware. Additionally, Java’s strict compile-time and
runtime checks help catch errors early, making Java programs reliable in enterprise
environments.
Java is widely used in enterprise environments, Android app development, and large-
scale distributed systems. Its robust performance and reliability have made it a mainstay
in financial services, e-commerce, and government systems. Moreover, the widespread
use of Java in academic settings and industry training programs ensures a steady influx
of skilled Java developers.
C++: Combining Performance with Abstraction
C++ was developed by Bjarne Stroustrup in the early 1980s as an extension of the C
language. The primary motivation behind C++ was to add object-oriented features to C,
without sacrificing the performance and control that C offers. Over the years, C++ has
evolved into a multi-paradigm language that supports procedural, object-oriented, and
generic programming.
C++ introduced classes, inheritance, and polymorphism, allowing developers to
create complex systems using objects. This object-oriented approach enables better
organization and reuse of code.
One of C++’s standout features is its support for generic programming through tem-
plates. Templates enable the writing of flexible and reusable code components, which
can operate with any data type. This feature is essential for creating libraries that are
both efficient and type-safe.
Like C, C++ offers low-level memory manipulation capabilities, giving developers
the power to fine-tune performance-critical applications. This makes C++ an excellent
choice for systems programming, game development, and applications where speed is
crucial.
C++ is often the language of choice for applications where performance is paramount.
It is extensively used in game development, real-time simulations, and high-performance
computing applications. Additionally, C++ remains prevalent in system-level program-
ming and is the backbone of many performance-critical libraries and frameworks.

JavaScript: The Language of the Web


JavaScript was created by Brendan Eich in 1995 at Netscape and quickly evolved to
become the cornerstone of interactive web development. Originally designed as a simple
scripting language for the browser, JavaScript has since grown into a versatile, full-stack
programming language that is used on both the client and server sides.
JavaScript is a dynamically typed, interpreted language, which allows for flexible
coding practices and rapid prototyping. Its dynamic nature makes it easy to manipulate
web page elements in real time.
One of JavaScript’s defining characteristics is its event-driven model, which is essen-
tial for building responsive web applications. The language also supports asynchronous
programming, enabling smooth handling of tasks like network requests and user input
without freezing the user interface.
JavaScript benefits from a vast ecosystem of frameworks and libraries, such as React,
Angular, and Vue for front-end development, and Node.js for server-side applications.
This ecosystem continues to expand, driving innovation in web technologies.
JavaScript is ubiquitous in modern web development. It powers interactive web-
sites, web applications, and even mobile apps through frameworks like React Native.
With the advent of Node.js, JavaScript has also become a significant player in back-
end development, enabling developers to use a single language across the entire stack.
Its versatility and widespread adoption make JavaScript a critical tool in the modern
developer’s toolkit.
16 L E C T URE 1: INTRODUCTION TO PROGRAMMING

Algorithms and Flowcharts


Algorithms and flowcharts are two fundamental concepts in computer science and
software engineering that play critical roles in designing, understanding, and communi-
cating solutions to complex problems. An algorithm is essentially a finite sequence of
well-defined instructions or steps designed to perform a specific task or solve a particular
problem. Its importance lies in the precision and clarity it brings to problem-solving,
ensuring that every step is explicitly defined and that the overall process is logically
sound. In contrast, a flowchart is a graphical representation of an algorithm that uses
standardized symbols to depict the various operations, decisions, and paths taken dur-
ing the execution of a process. Together, these tools form a cohesive methodology for
planning, analyzing, and implementing systems in both academic and professional
settings.
At its core, an algorithm represents a methodical procedure that takes an input,
processes it according to a series of logical steps, and produces an output. This sequence
of instructions must be unambiguous and finite, meaning that it always comes to a
conclusion after a specific number of steps. Historically, algorithms have been the subject
of study long before the advent of modern computers, dating back to ancient times
when mathematicians developed methods for arithmetic calculations and geometric
constructions. With the advent of computers, the design and analysis of algorithms
became a formal discipline, emphasizing not only correctness but also efficiency in
terms of time and memory usage. Today, algorithms are at the heart of almost every
software application, ranging from simple tasks like sorting and searching to more
complex operations in machine learning, data processing, and network routing.
Flowcharts serve as a bridge between the abstract logic of an algorithm and its
concrete implementation. By translating the sequential steps of an algorithm into a
visual format, flowcharts provide a clear, intuitive way to understand the flow of control
and the relationships between different parts of a process. In a typical flowchart, various
shapes are used to represent distinct types of operations: ovals or rounded rectangles
denote the start and end points of the process, rectangles indicate processing steps
or instructions, diamonds represent decision points that require a yes-or-no answer,
and parallelograms are often used to symbolize input and output operations. This
standardized use of symbols not only helps in creating a universal language that can be
understood by anyone familiar with the conventions but also aids in the identification
of potential problems, such as logical errors or inefficiencies, within the algorithm.
In practice, the process of designing an algorithm often begins with a thorough
analysis of the problem. A programmer or analyst will break down the problem into
smaller, more manageable components, devising a solution for each subproblem before
integrating them into a comprehensive strategy. It is during this phase that the use
of flowcharts can be particularly beneficial. Drawing a flowchart forces the designer
to lay out each step of the process clearly, ensuring that all possible outcomes and
decision points are accounted for. This visualization not only aids in clarifying the
overall structure of the algorithm but also serves as a preliminary check for logical
consistency. By examining the flowchart, one can readily identify loops, conditional
branches, and potential dead ends, all of which might require further refinement before
actual coding begins.
The educational value of algorithms and flowcharts is profound. Students learning
programming are often introduced to pseudocode as a stepping stone between natural
language and formal coding. Pseudocode allows learners to articulate their solution
strategies without worrying about the syntax of a specific programming language. Com-
plementing pseudocode with flowcharts provides an additional layer of understanding,
as the visual representation helps solidify the logical flow of ideas. This dual approach
not only reinforces the connection between abstract problem-solving and concrete im-
plementation but also encourages students to think critically about the efficiency and
clarity of their solutions. Moreover, flowcharts serve as an excellent tool for communica-
tion in collaborative environments. When working on complex projects, team members
from diverse backgrounds can refer to the flowchart to gain a quick, intuitive under-
standing of how a particular process is intended to work, even if they are not experts in
the underlying programming language.
Beyond educational settings, algorithms and flowcharts are indispensable in the soft-
ware development lifecycle. In the early stages of design, flowcharts help stakeholders
visualize the system architecture and the sequence of operations, facilitating discussions
about requirements, constraints, and potential improvements. During the implementa-
tion phase, a well-documented flowchart can serve as a guide for developers, reducing
the likelihood of misinterpretation and errors in the code. In debugging and mainte-
nance, flowcharts offer a roadmap that can be followed to isolate problematic areas in
the algorithm. They allow developers to trace the execution path and understand how
different conditions affect the outcome, which is especially useful in large-scale systems
where multiple modules interact in complex ways.
The role of algorithms in optimizing performance is another critical area of interest.
With the ever-increasing volume of data and the demand for real-time processing, the
efficiency of an algorithm can significantly impact the overall performance of a sys-
tem. Developers spend considerable time analyzing algorithms to ensure that they not
only produce correct results but do so within acceptable time and resource constraints.
Techniques such as divide and conquer, dynamic programming, and greedy methods
have been developed to tackle problems more efficiently. Each of these techniques has
its own set of trade-offs, and the choice of an algorithm often depends on the specific
requirements of the application. Flowcharts, in this context, help visualize the flow of
control and identify sections where performance bottlenecks may occur. By simplifying
complex decision paths into clear visual steps, flowcharts provide insights that can lead
to more streamlined and efficient algorithm designs.
The evolution of technology has also influenced the way algorithms and flowcharts
are used in modern software development. Contemporary integrated development
environments (IDEs) and computer-aided design tools have automated many aspects
of algorithm visualization and analysis. These tools can generate flowcharts directly
from source code, offering dynamic representations that update as the code changes.
Such automation not only saves time but also ensures that the documentation remains
consistent with the actual implementation. As software systems grow in complexity,
the integration of algorithm design with visual modeling tools becomes increasingly
important for managing large codebases and ensuring that systems remain maintainable
over time.
Algorithms and flowcharts are inseparable components of systematic problem solving
18 L E C T URE 1: INTRODUCTION TO PROGRAMMING

and software development. Algorithms provide the detailed, step-by-step instructions


necessary to solve problems efficiently, while flowcharts translate these instructions
into a visual format that enhances understanding and communication. Together, they
form a robust framework that is essential not only for writing and debugging code but
also for planning and optimizing the design of complex systems. From the early days of
computing to modern applications in data science, artificial intelligence, and beyond,
the principles underlying algorithms and flowcharts continue to be relevant. Their ability
to clarify logic, streamline processes, and facilitate collaboration makes them enduring
tools in the ever-evolving landscape of technology.

Summary
Programming languages are the fundamental tools that allow developers to instruct
computers to perform tasks and solve problems. They enable the translation of human
ideas into executable code and can range from low-level languages, like assembly, which
provide direct control over hardware, to high-level languages, like Python, Java, and C++,
which offer abstractions that simplify development. These languages are broadly catego-
rized by their level of abstraction, execution methods, and programming paradigms.
Low-level languages, including machine and assembly languages, offer precise con-
trol and efficiency, making them ideal for tasks that require direct hardware manip-
ulation, such as operating system development and embedded systems. High-level
languages, on the other hand, prioritize developer productivity and readability, enabling
faster prototyping and easier maintenance. Additionally, the execution model of a lan-
guage—whether it is compiled, interpreted, or employs a hybrid approach—affects how
code is transformed into machine instructions and ultimately influences the perfor-
mance and flexibility of the final application.
Programming paradigms further distinguish languages by their approach to problem-
solving. Procedural programming focuses on step-by-step instructions, while object-
oriented programming organizes code around objects and classes to promote modularity
and reuse. Functional programming emphasizes the evaluation of functions and im-
mutability, and logic programming bases computation on formal logic. Many modern
languages are multi-paradigm, allowing developers to choose the most effective strategy
for a given problem.
The applications of programming languages are vast and diverse. In web develop-
ment, languages like JavaScript, HTML, and CSS work together to create interactive
and dynamic websites and web applications. Mobile applications are commonly de-
veloped using languages such as Java, Kotlin, Swift, or Dart, tailored for different plat-
forms. Desktop software, including productivity tools and operating systems, often relies
on languages like C++, C#, and Java for their performance and robustness. In game
development, languages like C++ and C# are essential for creating high-performance,
interactive environments. Moreover, specialized languages like SQL are crucial for man-
aging databases, while languages such as R, MATLAB, and Python dominate the fields of
scientific computing, data analysis, and machine learning.
In essence, the choice of programming language is determined by factors such as the
desired level of control, ease of use, performance requirements, and the specific domain
of application. Whether it is developing a simple script to automate everyday tasks or
designing complex systems for enterprise solutions, programming languages remain
indispensable in the continuous evolution of technology.

Types of Programming Errors


Syntax Errors
Syntax errors in programming occur when code violates the grammatical rules of a
programming language, preventing the compiler or interpreter from understanding and
executing it. These errors arise during the initial parsing phase, well before any of the
program’s logic is executed. For example, missing semicolons, misplaced parentheses,
or incorrect indentation in languages such as C, Java, or Python are common sources of
syntax errors. In C-based languages, a forgotten semicolon at the end of a statement may
lead to a cascade of errors, as the compiler struggles to determine where one statement
ends and another begins. In Python, the absence of a colon after a control structure
declaration, or improper indentation, can halt execution and force the programmer to
revise the code.
The strict nature of programming language syntax is designed to ensure that ev-
ery instruction is unambiguous and interpretable by the machine. Each language has
its own set of syntactic rules, which act as a contract between the programmer and
the computer. When these rules are broken, the programming environment typically
provides an error message that includes a line number and a brief description of the
problem. Although these messages can sometimes seem cryptic to beginners, they are
invaluable in guiding programmers to the source of the error. This immediate feedback
encourages the development of disciplined coding habits and a deeper understanding
of the language’s structure.
While syntax errors are often viewed as hurdles in the learning process, they serve
an essential role in improving code quality. The process of identifying and correcting
syntax errors forces developers to pay close attention to the precise details of language
syntax. This attention to detail is crucial not only for writing error-free code but also
for creating programs that are maintainable and scalable. Even experienced developers
encounter syntax errors, though they tend to resolve them quickly through familiarity
with the language’s rules. Moreover, the occurrence of syntax errors acts as an early
warning system that prevents ill-formed code from progressing to more complex stages
of execution where the errors could become more difficult to trace.
Modern development tools have significantly alleviated the burden of syntax errors.
Integrated development environments (IDEs) offer real-time syntax highlighting, auto-
completion, and linting features that alert developers to potential mistakes as they
write code. These features not only speed up the debugging process but also serve as a
constant reminder of the language’s syntactic rules, helping programmers internalize
them over time. Despite the sophistication of these tools, understanding the underlying
principles of syntax remains indispensable. Relying solely on automated assistance can
sometimes obscure the deeper knowledge of how the language is structured, which is
necessary for tackling more intricate programming challenges.
In essence, syntax errors are a natural and instructive part of the programming
process. They enforce the rigorous standards required for a computer to interpret and
20 L E C T URE 1: INTRODUCTION TO PROGRAMMING

execute human-written instructions accurately. Although encountering syntax errors can


be frustrating, each error provides an opportunity for learning and growth. As developers
gain experience, they become more adept at recognizing and preventing these errors,
leading to a smoother and more efficient coding experience. Ultimately, the discipline
enforced by syntax errors not only improves individual code quality but also contributes
to the overall robustness and reliability of software systems.

Logical Errors
Logical errors in programming refer to mistakes in the design or implementation of
an algorithm that lead to incorrect or unexpected outcomes, even though the code
compiles and runs without generating any syntax or runtime errors. Unlike syntax
errors, which are immediately flagged by a compiler or interpreter due to violations of a
language’s grammatical rules, logical errors stem from flaws in the reasoning process
behind the code. This means that while the program follows the written instructions
without interruption, it fails to deliver the intended results.
At the heart of logical errors lies the discrepancy between the programmer’s intended
solution and the actual behavior of the code. These errors can occur in various parts of
a program, such as in conditional statements, loops, or during the manipulation of data
structures. For instance, an off-by-one error in a loop—a common logical error—might
cause a program to process one element too many or too few. Similarly, a flawed con-
dition in an if-statement might lead the program to execute the wrong block of code,
resulting in incorrect processing of data or unexpected outcomes. Because the code itself
is syntactically correct, these mistakes often escape the automated checks performed by
compilers and require careful review and testing to detect.
Detecting logical errors usually involves thorough testing and debugging. Program-
mers may use techniques such as stepping through the code with a debugger, printing
variable values at critical points, or writing unit tests that compare actual outputs to
expected ones. By verifying that each component of the code behaves as intended,
developers can gradually narrow down the source of the error. Logical errors often man-
ifest when the real-world usage of a program deviates from the scenarios anticipated
during development. For this reason, comprehensive testing—including edge cases and
unexpected inputs—is vital for uncovering these subtle issues.
The causes of logical errors are diverse. They may arise from a misunderstanding of
the problem requirements, misinterpretation of how a particular programming construct
works, or oversights in the algorithm’s design. Sometimes, a logical error results from
assumptions that hold true only under certain conditions, which can lead to failures
when those conditions change. Additionally, complex algorithms with multiple inter-
acting components are especially prone to logical errors because the interplay between
various parts of the code can create unforeseen complications.
Addressing logical errors requires a disciplined approach to coding. Good program-
ming practices, such as clear code documentation and maintaining modular, well-
structured code, can help prevent these errors from occurring. When the intended
behavior of a piece of code is clearly documented, it becomes easier for the programmer
to verify that the implementation aligns with that behavior. Peer code reviews and pair
programming are also effective strategies for identifying logical errors; fresh eyes can
often spot inconsistencies or flaws that the original author may have overlooked.
Moreover, logical errors highlight the importance of designing with precision. A
robust algorithm should not only be efficient but also accurately reflect the underlying
problem it is meant to solve. This demands a clear understanding of both the problem
domain and the logical constructs used to address it. Developers are encouraged to plan
their approach meticulously, often starting with pseudocode or flowcharts to outline
the logical steps before writing the actual code. Such preparatory work can reduce the
likelihood of logical errors by ensuring that the algorithm’s structure is sound and that
each step logically follows from the previous one.

Runtime Errors
Runtime errors in programming occur when a program is executed and an unexpected
situation arises that causes the program to crash or behave unpredictably. Unlike syntax
or compile-time errors, which are caught before a program runs, runtime errors only
reveal themselves during execution when the program encounters a scenario it cannot
handle. One common cause of runtime errors is the attempt to perform an illegal
operation, such as dividing by zero or accessing an array element outside its valid index
range. These errors manifest only under specific conditions and inputs, making them
sometimes challenging to predict during the development process.
At the heart of runtime errors is the fact that they occur when the program’s logic
meets unforeseen conditions during its execution. For example, if a program attempts
to open a file that does not exist, a runtime error will occur because the operation
cannot be completed as specified. Similarly, trying to use a null reference to access an
object’s property can lead to a null pointer exception, causing the program to terminate
abruptly. These types of errors underscore the importance of validating inputs, checking
preconditions, and handling exceptional cases gracefully in code.
Debugging runtime errors typically involves a combination of systematic testing,
logging, and the use of debugging tools provided by development environments. Devel-
opers often insert logging statements throughout the code to record the program’s state
at various points, which helps identify where the error occurs. In many cases, integrated
development environments (IDEs) offer debugging tools that allow developers to step
through the code line by line, inspect variable values, and monitor the control flow. This
process can be invaluable in isolating the specific conditions that trigger the runtime
error.
Handling runtime errors effectively also requires implementing robust error handling
strategies. Exception handling mechanisms, such as try-catch blocks in many modern
programming languages, allow developers to catch errors as they occur and respond in a
controlled manner. Instead of letting the program crash, these mechanisms can provide
meaningful error messages, perform necessary cleanup, or even recover from the error
to continue running the application. This proactive approach to error management is
particularly important in large-scale applications, where an unhandled runtime error
can have significant consequences, including data loss or system downtime.
Furthermore, thorough testing—including unit tests, integration tests, and stress
tests—plays a critical role in identifying potential runtime errors before a program is
deployed. By simulating a variety of scenarios, including edge cases and unexpected
22 L E C T URE 1: INTRODUCTION TO PROGRAMMING

inputs, developers can ensure that their code behaves as expected under a wide range
of conditions. This testing not only helps in catching runtime errors early but also
contributes to building a more resilient and stable application.

Practice Questions
1. What is computer programming, and why is it essential in today’s technology-
driven world?

2. How do algorithms contribute to solving problems in computer programming, and


what characteristics make an algorithm effective?

3. What are the primary differences between compiled languages and interpreted
languages, and how do these differences affect performance and development
speed?

4. In what ways does a compiler work, and what are its key roles in translating high-
level code into machine-readable instructions?

5. How do integrated development environments (IDEs) enhance the programming


process, and what features do they typically offer to developers?

6. What are the main programming paradigms—such as procedural, object-oriented,


functional, and logic programming—and how do they influence the structure and
organization of code?

7. How does object-oriented programming (OOP) promote code reuse, modularity,


and scalability in software development?

8. What strategies and tools can programmers use to debug code effectively and
manage errors during the development lifecycle?

9. In what ways do flowcharts and pseudocode facilitate the planning and design of
algorithms before actual coding begins?

10. How do version control systems contribute to collaboration and project manage-
ment in programming, and what are some common systems used today?

11. How do domain-specific languages differ from general-purpose programming


languages, and what benefits do they offer in their specialized fields?

12. In what ways has the evolution of programming languages influenced modern
software development practices and the overall advancement of technology?
Lecture 2: Hello World

Programming using Python


Python is a high-level, interpreted programming language that has become one of the
most popular and versatile tools in the world of software development. Its design phi-
losophy emphasizes code readability, simplicity, and productivity, making it an excellent
choice for both beginners and experienced developers. Over the years, Python has
evolved to meet the growing demands of modern computing, proving its worth in a wide
range of applications, from web development and data science to artificial intelligence
and scientific computing. In this discussion, we explore the purpose behind Python’s
design, trace its evolution through various versions, and examine the diverse range of
problems that Python is uniquely suited to solve.
Python was originally developed in the late 1980s by Guido van Rossum, with the goal
of creating a language that could bridge the gap between the simplicity of scripting lan-
guages and the power of compiled languages. Van Rossum aimed to design a language
that allowed programmers to express concepts in fewer lines of code than would be
required in languages like C or Java. The result was a language that was both accessible
and powerful, allowing developers to quickly prototype applications while still main-
taining the ability to build large, scalable systems. Python’s purpose has always been
to facilitate rapid development and clear programming practices. It is used extensively
in academic research, industry, and even in hobbyist projects due to its low barrier to
entry and its wide-ranging capabilities.
The evolution of Python can be best understood by looking at its major versions,
each of which has brought significant improvements and new features to the language.
The journey began with Python 1.0, released in 1994, which introduced core features
such as exception handling, functions, and modules. Python 1.x established the foun-
dation of the language with its emphasis on simplicity and readability. As the language
matured, Python 2.0 was released in 2000, bringing many enhancements such as list
comprehensions, garbage collection, and a more robust standard library. Python 2.x was
widely adopted in the industry and served as the backbone for countless projects for
over a decade.
Despite its success, Python 2.x eventually reached the end of its life cycle, as the
needs of modern software development evolved. This led to the release of Python 3.0
in 2008, a version that introduced significant changes aimed at removing redundant
programming constructs and modules, as well as addressing long-standing design flaws.
Python 3.x offers improved support for Unicode, better handling of data types, and more
consistent behavior across the language’s features. Although the transition from Python
2 to Python 3 was challenging for some legacy systems, the improvements in Python 3
have made it the clear choice for new projects and developments. Today, the Python
community continues to enhance the language with regular updates and improvements,
24 L E C T URE 2: HELLO WORLD

ensuring that Python remains at the forefront of modern programming.


One of the most compelling aspects of Python is the wide array of problems it can
solve. Python’s versatility is one of its greatest strengths, and it has been successfully
applied in many domains. In the realm of web development, Python is the language
behind powerful frameworks such as Django and Flask, which allow developers to build
complex, scalable web applications with relative ease. These frameworks provide built-
in support for tasks like database interactions, URL routing, and session management,
enabling rapid development cycles and reducing the time it takes to bring an idea to
fruition. By simplifying many of the common tasks in web development, Python has
become a favorite among startups and established companies alike.
Data science and machine learning are other areas where Python shines. With the
rise of big data, Python’s robust libraries such as NumPy, Pandas, and SciPy have made
it the language of choice for data analysis, statistical modeling, and scientific research.
The availability of powerful machine learning libraries like scikit-learn, TensorFlow, and
PyTorch has further cemented Python’s role in the artificial intelligence revolution. Re-
searchers and practitioners can leverage these tools to build predictive models, perform
complex data visualizations, and experiment with new algorithms without having to
worry about the intricacies of memory management or low-level programming. Python’s
clear syntax and extensive ecosystem of libraries have democratized data science, allow-
ing experts from a variety of fields to harness the power of machine learning and deep
learning.
In addition to web development and data science, Python has found applications
in systems automation, scripting, and even game development. System administrators
often use Python scripts to automate routine tasks, such as file manipulation, network
monitoring, and system configuration, thereby improving efficiency and reducing the
likelihood of human error. Python’s ability to quickly handle text processing and its
extensive support for various file formats make it an invaluable tool for automating
workflows in complex environments. In the field of education, Python’s simplicity and
readability have made it a popular choice for teaching programming fundamentals.
Many universities and coding boot camps use Python as the introductory language for
students, enabling them to grasp essential concepts without being overwhelmed by
syntactical complexities. Even in game development, where performance is a critical
concern, Python is used for scripting and prototyping, allowing developers to experiment
with gameplay mechanics and design features before committing to more performance-
intensive languages.
Python’s wide applicability is also evident in scientific computing. Researchers in
fields ranging from astrophysics to biology rely on Python for simulations, data analysis,
and modeling complex systems. The language’s ability to integrate with other tools
and languages means that it can be used to glue together different parts of a research
pipeline, from data collection to visualization and interpretation. Libraries such as Mat-
plotlib for data visualization and Jupyter Notebooks for interactive computing have made
Python an indispensable tool in scientific research. The open-source nature of Python
and its libraries encourages collaboration among researchers worldwide, fostering an
environment where scientific discoveries can be shared and built upon.
While Python’s strengths are numerous, it is important to acknowledge some of
the challenges that come with using the language. Python is an interpreted language,
which can sometimes result in slower execution times compared to compiled languages
like C or C++. For applications where performance is critical, this can be a significant
drawback. However, there are ways to mitigate this issue, such as using optimized
libraries, implementing performance-critical sections in C, or leveraging just-in-time
(JIT) compilers like PyPy. Another potential challenge with Python is its dynamic typing,
which, while increasing flexibility and ease of use, can also lead to runtime errors that
might have been caught at compile time in statically typed languages. This trade-off is
often mitigated by thorough testing and the use of tools like type checkers (e.g., mypy)
to enforce type annotations in larger projects.
Despite these challenges, the benefits of Python far outweigh its drawbacks for many
applications. Its ability to solve complex problems across multiple domains, combined
with its ease of learning and expansive community support, has led to its widespread
adoption. Whether used for rapid prototyping, developing robust web applications,
conducting cutting-edge research, or automating repetitive tasks, Python has proven to
be a reliable and powerful tool in the programmer’s arsenal.

Setting Up Your Python Environment


To write Python programs on your computer, you’ll need a few key components and
tools:

1. Python Interpreter: The first step is to install the Python interpreter, which is
responsible for running your Python code. You can download the latest version of
Python from the official Python website (https://www.python.org/downloads/).
The installer is available for various operating systems such as Windows, macOS,
and Linux. During installation, you may have the option to add Python to your
system’s PATH, which makes it easier to run Python from the command line.

2. A Code Editor or Integrated Development Environment (IDE): While you can write
Python code in any text editor, using a code editor or IDE can greatly enhance
your productivity by providing features like syntax highlighting, code completion,
debugging tools, and integrated terminal support. Some popular choices include:

• Visual Studio Code (VS Code): A free, lightweight editor with extensive exten-
sions for Python.
• PyCharm: A powerful IDE specifically designed for Python development,
available in both free (Community) and paid (Professional) versions.
• Sublime Text or Atom: Both are popular text editors that support Python with
additional plugins.
• Jupyter Notebook: Ideal for data analysis, scientific computing, and interac-
tive programming, it allows you to combine code, text, and visualizations in
one document.

3. Setting Up Your Environment: Once you have Python installed and your preferred
editor or IDE set up, you’ll need to familiarize yourself with running Python pro-
grams. This typically involves:
26 L E C T URE 2: HELLO WORLD

• Writing your Python code in a file with a .py extension.


• Running the code using the command line (by typing python filename.py or
python3 filename.py, depending on your installation) or directly within your
IDE, which usually provides a “Run” button.
• For interactive work, you might also use the Python REPL (Read-Eval-Print
Loop), which you can access by simply typing python or python3 in your
terminal.
4. Optional Tools and Libraries: Depending on the projects you plan to work on, you
might need additional libraries or tools. Python comes with a package manager
called pip, which you can use to install external libraries (such as NumPy for
numerical computing, Flask for web development, or Pandas for data analysis).
Setting up a virtual environment using venv or tools like conda can help manage
dependencies for different projects.
5. Learning Resources: Finally, if you’re just getting started, consider utilizing the
wealth of resources available for learning Python. Online tutorials, official docu-
mentation, and community forums can be invaluable as you develop your pro-
gramming skills.

Hello World
Below is a simple "Hello, World!" program written in Python:
p r i n t ( " H e l l o , World ! " )
This program consists of a single line of code that uses Python’s built-in print()
function. The print() function outputs the text provided to it—in this case, the string
"Hello, World!"—to the console or terminal. When you run this program, it will display
the message "Hello, World!" on the screen. This simple example is traditionally used as
an introductory exercise for beginners to verify that their programming environment is
set up correctly and to get familiar with the basic syntax of the language.

How to Run the Program


1. Save the Code in a File: Create a new file using your preferred text editor or Inte-
grated Development Environment (IDE), and save the file with a .py extension (for
example, hello_world.py).
2. Open a Terminal or Command Prompt: Navigate to the directory where you saved
the file. For instance, if your file is in the Documents folder, you would change the
directory to that folder.
3. Run the Program: Type the following command and press Enter:
On Windows or macOS (if Python is installed as python):
python h e l l o _ w o r l d . py

Alternatively, if Python 3 is installed as python3:


python3 h e l l o _ w o r l d . py

After running the command, you should see the output:


H e l l o , World !

This confirms that your Python environment is correctly set up and that the pro-
gram is running as expected.

In what follows, we will use python3 in all our examples.

A Simple Calculator
Below is an example of a simple calculator program written in Python 3. The program
directly executes its code in the global scope, prompting the user to select an operation,
input two numbers, perform the calculation, and display the result.
# Simple C a l c u l a t o r Program

# D i s p l a y a welcome message and l i s t a v a i l a b l e o p e r a t i o n s .


p r i n t ( " Welcome t o t h e Simple C a l c u l a t o r ! " )
p r i n t ( " P l e a s e s e l e c t an o p e r a t i o n : " )
print ( " 1 . Addition " )
print ( " 2 . Subtraction " )
print ( " 3 . Multiplication " )
print ( " 4 . Division " )

# Get t h e u s e r ’ s c h o i c e f o r t h e o p e r a t i o n .
c h o i c e = input ( " E n t e r c h o i c e ( 1 / 2 / 3 / 4 ) : " )

# Check i f t h e u s e r ’ s c h o i c e i s v a l i d .
i f c h o i c e in [ ’ 1 ’ , ’ 2 ’ , ’ 3 ’ , ’ 4 ’ ] :
# Prompt t h e u s e r t o e n t e r two numbers .
try :
num1 = f l o a t ( input ( " E n t e r t h e f i r s t number : " ) )
num2 = f l o a t ( input ( " E n t e r t h e second number : " ) )
except V a l u e E r r o r :
p r i n t ( " I n v a l i d i n p u t ! P l e a s e e n t e r numeric v a l u e s . " )
e x i t ( ) # E x i t t h e program i f c o n v e r s i o n f a i l s .

# Perform t h e c a l c u l a t i o n b a s e d on t h e u s e r ’ s c h o i c e .
i f c h o i c e == ’ 1 ’ :
r e s u l t = num1 + num2
operator = ’+ ’
e l i f c h o i c e == ’ 2 ’ :
r e s u l t = num1 − num2
o p e r a t o r = ’− ’
e l i f c h o i c e == ’ 3 ’ :
r e s u l t = num1 * num2
operator = ’ * ’
e l i f c h o i c e == ’ 4 ’ :
# Check f o r d i v i s i o n by z e r o .
i f num2 == 0 :
p r i n t ( " E r r o r : D i v i s i o n by z e r o i s not a l l o w e d . " )
exit ()
28 L E C T URE 2: HELLO WORLD

r e s u l t = num1 / num2
operator = ’ / ’

# Display the r e s u l t of the calculation .


p r i n t ( f " { num1 } { o p e r a t o r } { num2 } = { r e s u l t } " )
else :
# Inform t h e u s e r i f an i n v a l i d c h o i c e was made .
p r i n t ( " I n v a l i d c h o i c e ! P l e a s e run t h e program a g a i n and s e l e c t a v a l i d o p e r a t i o n . " )

Detailed Description of Each Part of the Code

1. Welcome and Operation List: The program starts with a series of print() state-
ments that display a welcome message and list the four available arithmetic oper-
ations—addition, subtraction, multiplication, and division. This introduction is
intended to guide the user through the available options for calculations.

2. User Choice Input: The input() function is used to prompt the user to enter a
choice corresponding to one of the listed operations. The input is stored in the
variable choice. The program then checks whether the entered choice is valid (i.e.,
whether it is one of the strings ’1’, ’2’, ’3’, or ’4’).

3. Validating and Converting Number Inputs: If the user’s choice is valid, the program
proceeds to prompt the user to enter two numbers. Each input is converted to a
floating-point number using the float() function. This conversion is wrapped in
a try block to catch any ValueError that occurs if the user enters a non-numeric
value. If such an error occurs, an error message is displayed, and the program
terminates by calling exit().

4. Performing the Calculation: Using a series of if and elif statements, the program
determines which arithmetic operation to perform based on the user’s choice:

• Addition (choice ’1’): The two numbers are added together.


• Subtraction (choice ’2’): The second number is subtracted from the first.
• Multiplication (choice ’3’): The two numbers are multiplied.
• Division (choice ’4’): Before performing the division, the program checks if
the second number (num2) is zero to prevent a division by zero error. If num2
is not zero, it performs the division.

5. In each case, the result of the calculation is stored in the variable result, and a
corresponding operator symbol (e.g., ’+’, ’-’, ’*’, or ’/’) is stored in the variable
operator for later display.

6. Displaying the Result: After the calculation is completed, the program uses a
formatted string (an f-string) to print the complete arithmetic expression along
with the result. For example, if the user inputs 5 and 3 for addition, the output will
be:
5.0 + 3.0 = 8.0
7. Handling Invalid Choices: If the initial input for the operation is not one of the
valid options, the program outputs an error message instructing the user to run
the program again and select a valid operation.

Block Indentation In Python


Block indentation in Python is a fundamental aspect of its syntax and plays a critical
role in structuring code. Unlike many other programming languages that rely on explicit
symbols such as curly braces to define blocks of code, Python uses indentation to indicate
where blocks begin and end. This design choice enforces a uniform style that improves
readability and reduces the likelihood of errors caused by misplaced or mismatched
delimiters.
In Python, any statement that introduces a new block—such as an if statement, a for
or while loop, or a function definition—must be followed by a group of indented lines
that form the body of that block. The amount of indentation is not fixed by the language
itself; however, consistency is key. Typically, developers use four spaces per indentation
level, and many style guides, including the widely respected PEP 8, recommend this
convention. If the indentation is inconsistent, the Python interpreter will raise an error,
which emphasizes the importance of maintaining clear and consistent indentation
throughout the code.
The use of indentation as a structural marker has several significant benefits. First, it
naturally enforces readability. When blocks of code are indented, the structure of the
program becomes immediately apparent to anyone reading the code. Nested blocks are
clearly visible, which makes understanding the flow of control in the program much
simpler. This clarity is especially beneficial in larger projects or when multiple developers
are collaborating, as it reduces ambiguity regarding which statements belong to which
blocks.
Another advantage of block indentation is that it minimizes syntactic clutter. Since
there is no need for extra characters like braces or end markers, the code remains clean
and uncluttered. This simplicity can lead to fewer errors, as there is less chance of
accidentally misplacing a delimiter. The enforced indentation also encourages program-
mers to think about the logical grouping of their code, resulting in more modular and
maintainable programs.
Moreover, block indentation in Python aids in debugging and code maintenance.
When an error occurs, it is often easier to locate the source of the problem in well-
indented code because the structure of the program is immediately apparent. If a block
is not indented correctly, the interpreter will typically point out the line where the
error occurs, guiding the developer to the issue more quickly. This immediate feedback
mechanism is invaluable, especially for beginners learning the language and developing
their coding skills.
The emphasis on indentation also cultivates discipline in programming practices.
Developers are encouraged to write code that adheres to a consistent style, which not
only benefits the individual by reducing errors but also benefits the team by establishing
a common coding standard. Over time, this practice leads to code that is easier to read,
review, and refactor.
30 L E C T URE 2: HELLO WORLD

Comments
Comments in Python are annotations added to the source code that are not executed by
the Python interpreter. Their primary purpose is to provide clarity and context, making
the code easier to understand for both the original programmer and others who may
work with it later. In Python, any text following the hash symbol (#) on a line is treated
as a comment and is ignored during execution. This simple convention encourages
developers to explain the purpose of complex code segments, note assumptions, or
highlight potential areas for future improvement.
Comments serve multiple important functions. They help document what a par-
ticular block of code is intended to do, which is especially useful when the logic is
intricate or not immediately obvious. This documentation is crucial during debugging
or maintenance, as clear comments can reduce the time needed to understand how
and why the code operates as it does. Additionally, when working in teams, comments
facilitate collaboration by ensuring that all members of the project have insights into
the design decisions and functionalities embedded within the code. Here is an example
of comments:
# T h i s i s a s i n g l e −l i n e comment i n Python
p r i n t ( " H e l l o , World ! " ) # I n l i n e comment

Python also supports multi-line comments or docstrings using triple quotes (”’ or
"""). These are often used to provide detailed explanations for modules, classes, or
functions, outlining their purpose, parameters, and return values. Such docstrings can
be accessed by developers through help functions or documentation generators, thereby
improving the overall quality of the project’s documentation.
Python does not have an official syntax for multiline comments in the same way that
some other languages do. However, you can achieve a similar effect using two common
approaches:

• Triple-Quoted Strings: You can use triple-quoted strings (using ”’ or """) to write
comments that span multiple lines. When these strings are not assigned to a
variable or used as a docstring for a module, class, or function, they are ignored by
the Python interpreter. For example:
"""
T h i s i s a m u l t i l i n e comment .
I t can span s e v e r a l l i n e s .
The i n t e r p r e t e r w i l l i g n o r e t h i s l i n e
"""
p r i n t ( " H e l l o , World ! " )

Although triple-quoted strings are often used as multiline comments, they are
technically string literals. When placed in the middle of your code without being
assigned, they don’t have any effect, which makes them useful for commenting
out blocks of text.

• Multiple Single-Line Comments: Another common approach is to use multiple


single-line comments by starting each line with the hash symbol (#). For example:
# T h i s i s a m u l t i l i n e comment .
# Each l i n e i s p r e c e d e d by a ’ # ’ symbol .
# T h i s method i s e x p l i c i t and c l e a r i n i t s i n t e n t .
p r i n t ( " H e l l o , World ! " )

Both methods effectively serve the purpose of multiline commenting, although


many style guides suggest using multiple single-line comments for clarity. In sum-
mary, while Python lacks a dedicated multiline comment syntax, these techniques
allow you to include multiline explanations or temporarily disable blocks of code.

Expressions
Expressions in Python are fundamental constructs that compute and return values from
various combinations of variables, literals, operators, and function calls. At their core,
an expression is any segment of code that can be evaluated to produce a value. For
example, simple expressions like 42 or "Hello" are straightforward, while more complex
expressions such as 3 + 5 * 2 involve arithmetic operators that dictate the order of
evaluation to yield a final result. Python’s dynamic nature allows expressions to combine
different data types, meaning that an expression can easily mix numbers, strings, and
even function outputs.
Expressions play a vital role throughout Python code. In assignment statements, the
right-hand side is an expression whose evaluated value is then stored in a variable; for
instance, in result = 3 + 5 * 2, the expression 3 + 5 * 2 is computed, and its value, 13, is
assigned to the variable result. They are also integral to control structures; conditions in
if, while, or for statements are expressions that must resolve to a Boolean value (True or
False), guiding the flow of the program.
Furthermore, expressions are used in function calls, list comprehensions, and lambda
functions, among other constructs, which underscores their ubiquity in Python pro-
gramming. Unlike statements, which perform an action, expressions always return a
value, making them ideal for embedding within other code constructs to achieve concise,
readable, and efficient programming patterns.

Variables
Variables in Python are fundamental components that allow programmers to store and
manipulate data during the execution of a program. A variable in Python is essentially a
name that references a value in memory, and it is created simply by assigning a value
to that name using the assignment operator (=). For example, writing x = 10 creates
a variable named x that holds the integer value 10. Unlike some other programming
languages, Python does not require an explicit declaration of a variable’s type; instead, it
uses dynamic typing, meaning that the interpreter determines the type of the variable
at runtime based on the assigned value. This flexibility enables programmers to write
concise and adaptable code without having to specify types explicitly.
The dynamic nature of Python variables also means that the type of a variable can
change during the execution of a program. For instance, a variable initially holding
an integer value can later be reassigned to hold a string or a list, such as by executing
x = "Hello, World!" or x = [1, 2, 3]. This characteristic provides convenience in many
32 L E C T URE 2: HELLO WORLD

coding scenarios but also requires that programmers remain mindful of the current state
and type of their variables to avoid type-related errors during operations that assume a
specific data type.
Python encourages a clear and readable style, and this extends to naming variables.
Variable names should be descriptive to enhance code readability and maintainability.
Although Python allows various naming conventions, it is recommended to follow the
guidelines outlined in PEP 8, which suggest using lowercase letters with words separated
by underscores (e.g., user_name or total_count). There are also certain reserved words in
Python—such as for, while, if, and else—that cannot be used as variable names because
they serve specific purposes in the language’s syntax.
Variables in Python also have scope, which determines the part of the code where
the variable is accessible. Variables defined in the global scope are accessible throughout
the entire program, while those defined within a function or block are limited to that
local context. Understanding the concept of scope is crucial, especially when dealing
with functions, modules, or classes, as it helps prevent naming conflicts and unintended
side effects.
In addition to holding primitive data types like integers, floats, and strings, Python
variables can reference more complex objects such as lists, dictionaries, sets, and even
custom objects created from classes. This flexibility allows programmers to model a
wide variety of data structures and perform operations on them using Python’s rich set
of built-in functions and methods.
Another important aspect of Python variables is that they are essentially references
to objects in memory. When a variable is assigned a value, it points to an object stored
in memory. If that object is mutable, like a list or dictionary, changes made through one
variable will reflect in all other variables referencing the same object. This behavior is
significant when writing functions and manipulating data structures, as it can influence
the program’s behavior in subtle ways.

Packages
Python packages are a core component of the Python ecosystem, providing a way to
bundle and distribute reusable code modules that extend Python’s functionality. At its
essence, a package is a directory containing one or more Python modules, along with a
special file named __init__.py that indicates to the Python interpreter that the directory
should be treated as a package. This structure allows developers to organize related code
together, making it easier to manage and maintain.
One of the most significant advantages of Python packages is that they promote code
reuse. Instead of writing everything from scratch, developers can leverage thousands of
existing packages to add complex functionality to their projects. For instance, packages
like NumPy and Pandas are widely used for numerical computations and data manipu-
lation, while Django and Flask provide robust frameworks for web development. This
ready availability of well-tested code not only accelerates development but also fosters a
community of shared solutions and best practices.
Installation and management of packages are streamlined by tools such as pip (the
Python Package Installer) and conda, a package manager that comes with the Anaconda
distribution. Pip connects to the Python Package Index (PyPI), a central repository
containing over 300,000 packages, enabling users to easily install or upgrade packages
with simple commands like pip install package_name. Additionally, virtual environ-
ments—created using tools like venv or virtualenv—allow developers to manage depen-
dencies for different projects without conflict. This isolation ensures that each project
has access to the correct versions of packages it requires, thus avoiding compatibility
issues.
Beyond the basic functionality of installing and importing packages, these tools often
provide mechanisms for dependency management and version control. For example, a
package’s requirements.txt file can list all dependencies required for a project, making
it easier to set up a consistent development environment. This is particularly benefi-
cial in collaborative settings where maintaining the same environment across different
machines is crucial.
Python packages also play a critical role in the open-source community. Many pack-
ages are developed and maintained by a diverse group of contributors around the world,
and they are often freely available under various open-source licenses. This collabora-
tive approach encourages innovation and the continuous improvement of the Python
ecosystem. Moreover, extensive documentation and active community forums around
popular packages make it easier for new users to learn how to implement advanced
functionality in their projects.
We will discuss Python packages in details later on Chapter 7.

Summary
Python is a high-level, interpreted programming language known for its clear syntax and
readability. At its core, Python emphasizes simplicity, making it an excellent language
for beginners while also being powerful enough for advanced development. One of its
fundamental features is dynamic typing, meaning that variables can hold values of any
data type without explicit type declarations. This flexibility allows developers to write
concise code, although it also requires careful handling to avoid type-related errors.
The language uses indentation to define code blocks instead of traditional braces,
enforcing a clean and consistent coding style. This design choice enhances readability
and helps maintain a clear structure in the code. Python supports a variety of basic
data types, including integers, floats, strings, booleans, and collections such as lists,
tuples, dictionaries, and sets. These data types allow for diverse operations and data
manipulations, forming the backbone of many Python programs.
Control flow in Python is managed with conditional statements (if, elif, else) and
loops (for, while), enabling developers to execute code conditionally or repetitively based
on specific criteria. Python’s straightforward syntax for these constructs makes it easy to
implement complex logic without overwhelming the reader. In addition, Python supports
the creation of functions using the def keyword, allowing programmers to encapsulate
code into reusable blocks. Functions enhance modularity and help in organizing code
effectively.
Comments in Python, indicated by the # symbol for single-line comments and triple
quotes for multi-line comments or docstrings, serve as important documentation tools.
They help explain the purpose and functionality of code sections, facilitating better
understanding and collaboration among developers.
34 L E C T URE 2: HELLO WORLD

Moreover, Python’s extensive standard library and its ecosystem of third-party mod-
ules and packages significantly broaden its capabilities. Whether for web development,
data analysis, machine learning, or automation, Python provides robust tools and frame-
works to handle a variety of tasks.
In summary, Python’s basic features—its dynamic typing, clear syntax with enforced
indentation, built-in data types, control structures, functions, and comprehensive li-
braries—make it a versatile and accessible language. Its simplicity and power allow
programmers to focus on solving problems efficiently, which has contributed to its
widespread adoption across various fields.

Practice Lab: Writing and Running a Simple Python


Program
• Objectives
– Understand how to write basic Python code.
– Learn how to use comments and variables.
– Save a Python script to a file.
– Run the script from a terminal or command prompt.
– Verify that the program produces the expected output.
• Prerequisites
– Python 3 must be installed on your computer. (Download from python.org)
– A simple text editor (such as Visual Studio Code, Sublime Text, Notepad++,
or even a basic text editor like Notepad) or an Integrated Development Envi-
ronment (IDE) like PyCharm.
– Basic familiarity with your operating system’s command line (Terminal on
macOS/Linux or Command Prompt/PowerShell on Windows).
• Lab Instructions

– Step 1: Create a New Python Script


1. Open Your Text Editor/IDE: Launch your preferred text editor or IDE.
2. Write the Code: In a new file, type the following code:
# T h i s i s a s i m p l e Python program t o p r i n t a g r e e t i n g .

# D e c l a r e a v a r i a b l e f o r t h e g r e e t i n g message .
g r e e t i n g = " H e l l o , World ! "

# Print the g r e e t i n g to the console .


print ( greeting )
Comments: Notice that lines starting with # are comments. They are
used to explain what the code does. Variable: The variable greeting is
assigned the string "Hello, World!". Output: The print() function is used
to display the greeting.
3. Save the File: Save the file with a descriptive name such as hello_world.py.
Make sure the file extension is .py.
– Step 2: Run Your Python Script
1. Open a Terminal or Command Prompt: On Windows: Open Command
Prompt or PowerShell. On macOS/Linux: Open Terminal.
2. Navigate to the File Location: Use the cd command to change to the
directory where your hello_world.py file is saved. For example:
cd path / t o / your / d i r e c t o r y

3. Run the Script: Execute your script by typing the following command
and pressing Enter:
On most systems where Python 3 is invoked by python3:
python3 h e l l o _ w o r l d . py

4. Verify the Output: You should see the output:


H e l l o , World !

This confirms that your script ran successfully.


– Step 3: Modify and Experiment
1. Change the Message: Modify the greeting variable in your code to another
message (e.g., "Hello, Python!") and run the program again.
2. Add Another Variable: Extend your script by adding another variable to
hold your name and print a personalized message. For example:
# T h i s program p r i n t s a p e r s o n a l i z e d g r e e t i n g .
greeting = " Hello "
name = " A l i c e "
p r i n t ( g r e e t i n g + " , " + name + " ! " )

3. Experiment with Comments: Add more comments to your script to ex-


plain each change. This practice helps reinforce the importance of clear
code documentation.

• Reflection Questions

– What does the print() function do in the program?


– How do comments help in understanding the code?
– What would happen if you removed the quotes around "Hello, World!"?
– How did modifying the variable values change the output of the program?

Practice Questions
1. Write a Python program that prints the message "Hello, World!" to the screen.

2. Create a variable named greeting with the value "Hello, Python!" and then print
this variable.
36 L E C T URE 2: HELLO WORLD

3. Write a program that declares two variables with numerical values. Compute and
print their sum, difference, product, and quotient.

4. Write a Python program that asks the user to enter their name and then prints a
welcome message using the entered name.

5. Write a Python script that begins with a single-line comment describing what the
script does (for example, "This script demonstrates basic variable assignment and
printing."). Then, assign a value to a variable and print it.

6. Create a Python program that declares two variables, assigns them numeric val-
ues, and performs an arithmetic operation (such as addition). Include an inline
comment next to the arithmetic operation that explains what the operation is
doing.

7. Write a Python file that starts with a triple-quoted string acting as a multiline
comment. In the comment, explain the purpose of the program. Then, declare at
least two variables (for example, a string and an integer) and print their values.

8. Write a short Python script where you declare a variable for your name and another
for your age. Use comments before each variable declaration to explain what each
variable represents. Finally, print a message that includes both variables.

9. Write a Python program that:


Starts with a comment describing the program’s functionality. Declares three
variables: one for a person’s name, one for their favorite color, and one for their
hometown. Uses inline comments to explain each step of the code. Prints a
formatted string that combines all three variables into a sentence.
Lecture 3: Conditional Statements: Making
Decisions

sectionWhat are Conditional Statements? Conditional statements in Python control the


flow of a program based on conditions. These statements execute different code blocks
depending on whether a condition evaluates to True or False. They are commonly used
in decision-making, loops, error handling, and other areas of programming. This logic
can be implemented using conditional statements.

Types of Conditional Statements in Python


Python provides the following types of conditional statements:
1. if Statement (Executes a block of code if the condition is True)

2. if-else Statement (Executes one block if True, another if False)

3. if-elif-else Statement (Handles multiple conditions)

4. Nested if Statement (An if inside another for complex decision-making)

5. if with Logical Operators (and, or, not)

If Statement(Single Condition Check)


The if statement checks whether a condition is True. If it is, the block of code inside the
if is executed. Otherwise, it is skipped

Syntax Statement
i f condition :
# Code b l o c k t h a t ru n s i f t h e c o n d i t i o n i s True

• The condition is an expression that evaluates to True or False.

• Python uses indentation to define the code inside the if block (usually 4 spaces or
a tab).

Example 1: Checking if a Number is Positive


num = 1 0
i f num > 0 :
p r i n t ( " The number i s p o s i t i v e . " )

• Output:
38 L E C T URE 3: CONDITIONAL STATEMENTS: MAKING DECISIONS

The number i s p o s i t i v e

Explanation:
• The condition num > 0 is True, so the message is printed.

• If num was negative or zero, nothing would be printed.

Example 2: Checking for Even Numbers


num = 8
i f num % 2 == 0 :
p r i n t ( " The number i s even . " )

• Output:

The number i s even .

• The number is positive

num % 2 == 0 c h e c k s i f t h e number i s even .


S i n c e 8 % 2 == 0 i s True , t h e message i s p r i n t e d .

Example 3: Checking if a Person is an Adult


age = 20
i f age >= 1 8 :
p r i n t ( " You a r e an a d u l t . " )

• Output:

You a r e an a d u l t .

Explanation:
• The condition
age >= 1 8 i s True , so " You a r e an a d u l t . "

is printed.

if-else Statement (Two Conditions - True or False)


Syntax Statement
i f condition :
# Code e x e c u t e s i f c o n d i t i o n i s True
else :
# Code e x e c u t e s i f c o n d i t i o n i s F a l s e

• If the condition evaluates to True, the if block runs.


• If the condition evaluates to False, the else block runs.

Example 1: Check if a Number is Positive or Negative


num = −5
i f num > 0 :
p r i n t ( " The number i s p o s i t i v e . " )
else :
p r i n t ( " The number i s n e g a t i v e . " )

• Output:

The number i s n e g a t i v e .
Explanation:
• Since
num > 0 i s F a l s e , t h e e l s e

– the else block executes instead.

Example 2: Check If a Number is Even or Odd


num = 7
i f num % 2 == 0 :
p r i n t ( " The number i s even . " )
else :
p r i n t ( " The number i s odd . " )

• Output:

The number i s n e g a t i v e .
Explanation:
• num % 2 == 0 c h e c k s i f t h e number i s even .

• S i n c e 7 % 2 == 0 i s F a l s e , t h e e l s e b l o c k runs .

Example 3: Login Authentication System


username = " admin "
password = " 1 2 3 4 "

i f username == " admin " and password == " 1 2 3 4 " :


p r i n t ( " Login S u c c e s s f u l " )
else :
print ( " Invalid Credentials " )

• Output:

Login S u c c e s s f u l
40 L E C T URE 3: CONDITIONAL STATEMENTS: MAKING DECISIONS

if-elif-else Statement (Multiple Conditions)


• The if-elif-else statement is used when we need to check multiple conditions.

Syntax Statement
i f condition1 :
# Code e x e c u t e s i f c o n d i t i o n 1 i s True
e l i f condition2 :
# Code e x e c u t e s i f c o n d i t i o n 2 i s True
e l i f condition3 :
# Code e x e c u t e s i f c o n d i t i o n 3 i s True
else :
# Code e x e c u t e s i f none o f t h e c o n d i t i o n s a r e True

• The program checks conditions from top to bottom.


• As soon as a True condition is found, the corresponding block executes, and the
rest are skipped.
• If none of the conditions are True, the else block runs.

Example 1: Grading System


marks = 85
i f marks >= 9 0 :
p r i n t ( " Grade : A" )
e l i f marks >= 8 0 :
p r i n t ( " Grade : B" )
else :
p r i n t ( " Grade : D" )

• Output:

Grade : B
Explanation:
• The program checks each condition sequentially.
marks >= 90 i s F a l s e , so i t moves t o t h e next c o n d i t i o n .
marks >= 80 i s True , so " Grade : B" i s p r i n t e d .

– Other conditions are skipped after a match is found.

Example 2: Checking Temperature Conditions


t e m p e r a t u r e = 30
i f temperature > 3 5 :
p r i n t ( " I t ’ s v e r y hot o u t s i d e ! " )
e l i f temperature > 2 5 :
p r i n t ( " The weather i s warm . " )
e l i f temperature > 1 5 :
print ( " I t ’ s cool outside . " )
else :
print ( " I t ’ s cold outside . " )
• Output:

The weather i s warm .

Explanation:
t e m p e r a t u r e > 35 i s F a l s e .
t e m p e r a t u r e > 25 i s True , so " The weather i s warm . " i s p r i n t e d .

• The remaining conditions are skipped.

Example 3: Checking the Type of a Triangle


a, b, c = 5, 5, 5

i f a == b == c :
print ( " E q u i l a t e r a l Triangle " )
e l i f a == b or b == c or a == c :
print ( " I s o s c e l e s Triangle " )
else :
print ( " Scalene Triangle " )

• Output:

Equilateral Triangle

Explanation:

• Since all sides are equal (a == b == c), the first condition is True, and "Equilateral
Triangle" is printed.

• The other conditions are skipped.

Example 4: Number Classification (Positive, Negative, or Zero)


num = −7

i f num > 0 :
p r i n t ( " P o s i t i v e number " )
e l i f num < 0 :
p r i n t ( " N e g a t i v e number " )
else :
p r i n t ( " Zero " )

• Output:

N e g a t i v e number

Explanation:

• num > 0 is False, so it moves to the elif block.

• num < 0 is True, so "Negative number" is printed.


42 L E C T URE 3: CONDITIONAL STATEMENTS: MAKING DECISIONS

• The else block is skipped.


Example 5: Ticket Pricing Based on Age
age = 1 2

i f age < 5 :
print ( " T i c k e t i s Free " )
e l i f age < 1 2 :
p r i n t ( " C h i l d T i c k e t P r i c e : $5 " )
e l i f age < 1 8 :
p r i n t ( " Teen T i c k e t P r i c e : $8 " )
else :
print ( " Adult Ticket Price : $12 " )

Output:
C h i l d T i c k e t P r i c e : $5

Explanation:
The f i r s t c o n d i t i o n age < 5 i s F a l s e .
The second c o n d i t i o n age < 1 2 i s True , so " C h i l d T i c k e t P r i c e : $5 " i s p r i n t e d .

• The rest of the conditions are skipped.

Nested if Statements (if Inside Another if )


• nested if statement is an if statement inside another if statement. It allows us to
check multiple conditions in a structured way.

Syntax Statement
i f condition1 :
i f condition2 :
# Code e x e c u t e s i f both c o n d i t i o n 1 and c o n d i t i o n 2 a r e True

• The inner if statement executes only if the outer if condition is True.

• If the outer if condition is False, the inner condition is not checked.

Example 1: Checking Even and Positive Numbers


num = 1 0
i f num > 0 :
p r i n t ( " P o s i t i v e number " )
i f num % 2 == 0 :
p r i n t ( " Even number " )

• Output:

P o s i t i v e number
Even number

Explanation:
• The first if checks if the number is positive.

• The second if (inside the first one) checks if the number is even.

Example 2:Checking for a Student’s Grade and Attendance


marks = 85
a t t e n d a n c e = 90

i f marks >= 8 0 :
p r i n t ( " You passed ! " )

i f a t t e n d a n c e >= 7 5 :
p r i n t ( " You a l s o have good a t t e n d a n c e . " )
else :
p r i n t ( " But your a t t e n d a n c e i s low . " )
else :
p r i n t ( " You f a i l e d . " )

• Output:

You passed !
You a l s o have good a t t e n d a n c e .

Explanation:

• marks >= 80 is True, so "You passed!" is printed.

• attendance >= 75 is also True, so "You also have good attendance." is printed.

Example 3: Login System with Nested if


username = " admin "
password = " 1 2 3 4 "

i f username == " admin " :


i f password == " 1 2 3 4 " :
p r i n t ( " Login S u c c e s s f u l ! " )
else :
p r i n t ( " I n c o r r e c t Password . " )
else :
p r i n t ( " Username not found . " )

• Output:

Login S u c c e s s f u l !

Explanation:

• The outer if checks if username == "admin". Since it’s True, it moves inside.

• The inner if checks if password == "1234", which is also True, so "Login Successful!"
is printed.
44 L E C T URE 3: CONDITIONAL STATEMENTS: MAKING DECISIONS

Using Logical Operators (and, or, not)


• Logical operators allow us to combine multiple conditions.

operators describtion Example


and Both conditions must be True x > 5 and x < 10
or At least one condition must be True x > 5 or x < 3
not Reverses the condition not (x > 5)
Example 1: Checking If a Number is Between Two Values (Using and)
num = 1 5

i f num > 1 0 and num < 2 0 :


p r i n t ( " The number i s between 1 0 and 2 0 . " )
else :
p r i n t ( " The number i s not i n t h e range . " )

• Output:

The number i s between 1 0 and 2 0 .

Explanation:

• num > 10 is True.

• num < 20 is True.

• Both conditions are True, so the if block runs

Example 2: Checking If a Number is Even or Negative (Using or)


num = −5

i f num % 2 == 0 or num < 0 :


p r i n t ( " The number i s e i t h e r even or n e g a t i v e . " )
else :
p r i n t ( " The number i s p o s i t i v e and odd . " )

• Output:

The number i s e i t h e r even or n e g a t i v e .

Explanation:

• num

• num < 0 (Checks if negative) is True

• Since or needs only one condition to be True, the if block runs.

Example 3: Checking Login Credentials (Using or)


username = " admin "
password = " p a s s 1 2 3 "

i f username == " admin " or username == " Admin " :


p r i n t ( " V a l i d username . " )
else :
p r i n t ( " I n v a l i d username . " )

• Output:

V a l i d username .

Explanation:

• Either "admin" or "Admin" is accepted.

• Since "admin" == "admin" is True, the if block runs.

Example 4: Checking If a Number is Within a Range


age = 1 6
i f age >= 1 3 and age <= 1 9 :
p r i n t ( " You a r e a t e e n a g e r . " )

• Output:

You a r e a t e e n a g e r .

Explanation:

• The and operator ensures both conditions must be true.

Real-World Applications of Conditional Statements


1. ATM Withdrawal System
b a l a n c e = 500
withdraw = 300

i f withdraw <= b a l a n c e :
print ( " Transaction successful ! " )
else :
print ( " I n s u f f i c i e n t balance ! " )

• Output:

Transaction successful !

2. Login Authentication
46 L E C T URE 3: CONDITIONAL STATEMENTS: MAKING DECISIONS

username = " admin "


password = " 1 2 3 4 "

i f username == " admin " and password == " 1 2 3 4 " :


p r i n t ( " Login S u c c e s s f u l " )
else :
print ( " Invalid Credentials " )

• Output:

Login S u c c e s s f u l

3. Traffic Light System


l i g h t = " red "
i f l i g h t == " g r e e n " :
p r i n t ( "Go" )
e l i f l i g h t == " y e l l o w " :
p r i n t ( " Slow down" )
else :
p r i n t ( " Stop " )

• Output:

Stop

Summary
Conditional statements in Python are essential for decision-making in programs, allow-
ing code to execute based on specific conditions. The main types include the if statement,
which runs a block of code when a condition is true, the if-else statement, which pro-
vides an alternative action if the condition is false, and the if-elif-else statement, which
checks multiple conditions sequentially. Additionally, nested if statements enable more
complex decision-making by placing one condition inside another. These structures
help control program flow, making applications more interactive and responsive.
In real-world applications, conditional statements are widely used in areas such as
authentication systems, where they verify login credentials, banking applications that
check account balances before processing transactions, and e-commerce platforms that
apply discounts based on purchase amounts. They are also crucial in gaming logic,
determining player progress, rewards, or in-game events. By mastering conditional
statements, programmers can create efficient, intelligent, and adaptable programs that
respond dynamically to user inputs and changing conditions.

Practice Lab: Writing and Running about if satatements


in Python Program
Objectives
• Understand and use if statements in Python.
• Write simple programs that use conditions to make decisions.

• Run and test Python programs with if statements.


Prerequisites
• Python installed (Download Python)

• A code editor (IDLE, VS Code, PyCharm, or Replit)

• Basic knowledge of Python syntax and variables


Lab Instructions

• Step 1: Create a Simple if Statement Program

1. Open your code editor.

2. Create a new file and name it.

3. Write the following Python program:

# Simple i f S t a t e m e n t : Check i f a number i s p o s i t i v e

# S t e p 1 : Get i n p u t from t h e u s e r
num = i n t ( input ( " E n t e r a number : " ) )

# S t e p 2 : Use an i f s t a t e m e n t t o c h e c k i f t h e number i s p o s i t i v e
i f num > 0 :
p r i n t ( " The number i s p o s i t i v e . " )

p r i n t ( " T h i s message a l w a y s p r i n t s . " ) # T h i s l i n e ru n s r e g a r d l e s s o f t h e c o n d i t i o n .

• Step 2: Run Your Python Program

Option 1: Running from an Editor (VS Code, PyCharm, IDLE)


1. Save the file

2. Click Run or press F5.


Option 2: Running from the Terminal/Command Prompt
1. Open the terminal or command prompt.

2. Navigate to the folder where your file is saved.

3. Run the program using:

python i f _ s t a t e m e n t . py

• Step 3: Test Your Program


48 L E C T URE 3: CONDITIONAL STATEMENTS: MAKING DECISIONS

Test Case 1: Input 5, the output should be:

E n t e r a number : 5
The number i s p o s i t i v e .
T h i s message a l w a y s p r i n t s .

Test Case 2: Input -3, the output should be:

E n t e r a number : −3
T h i s message a l w a y s p r i n t s .

• Step 4: Modify Your Program (Optional Challenge)

Enhance your program by checking if a number is negative or zero.

# Check i f a number i s p o s i t i v e , n e g a t i v e , o r z e r o

num = i n t ( input ( " E n t e r a number : " ) )

i f num > 0 :
p r i n t ( " The number i s p o s i t i v e . " )

i f num < 0 :
p r i n t ( " The number i s n e g a t i v e . " )

i f num == 0 :
p r i n t ( " The number i s z e r o . " )

Test Case 1: Input 0, output should be:

E n t e r a number : 0
The number i s z e r o .

Test Case 2: Input -7, output should be:

E n t e r a number : −7
The number i s n e g a t i v e .

Practice Questions
1. Write a Python program to check whether a character is a vowel or a consonant.

2. Write a program that asks the user for a password. If the password is correct, print
“Access Granted,” otherwise print “Access Denied.”

3. Write a program to check if a given number is divisible by both 5 and 11.

4. Create a program that takes in two numbers and an operator (+, -, *, /) and per-
forms the corresponding calculation.

5. Write a program that checks if a triangle is valid based on the sum of its angles.
6. Write a program to determine if a given number is a perfect square.

7. Create a program that takes three sides of a triangle and determines if it is an


equilateral, isosceles, or scalene triangle.

8. Write a Python program to determine if a number is prime.

9. Write a Python program that simulates a login system with multiple users.
50 L E C T URE 3: CONDITIONAL STATEMENTS: MAKING DECISIONS
Lecture 4: Loops: Repeating Tasks

Introduction
Loops are used to repeat a block of code multiple times. They help reduce repetition
and make programs efficient. Python provides two types of loops

1. for loop – Used for iterating over a sequence (lists, strings, ranges, etc.).

2. while loop – Runs until a condition becomes False.

for Loop
The for loop in Python is used to iterate over sequences like lists, tuples, strings, and
ranges. It automatically takes each item from the sequence and executes the loop body.
Syntax of for Loop.

f o r v a r i a b l e in sequence :
# Code t o e x e c u t e i n t h e l o o p

• The variable takes each value from the sequence (list, tuple, string, range, etc.).

• The loop runs for each item in the sequence.

Example 1: Using for Loop with a List


f r u i t s = [ " a p p l e " , " banana " , " c h e r r y " ]

f o r f r u i t in f r u i t s :
print ( f r u i t )

• Output:

apple
banana
cherry

Explanation:

• The loop picks each item (fruit) from the list and prints it.
52 L E C T URE 4: LOOPS: REPEATING TASKS

Example 2: Using for Loop with range()


f o r i in range ( 1 , 6 ) : # Numbers from 1 t o 5
print ( i )

• Output:

1
2
3
4
5

Explanation:

• range(1, 6) generates numbers from 1 to 5 (excluding 6).

Example 3: Iterating Over a String


word = " Python "

f o r l e t t e r in word :
print ( l e t t e r )

• Output:

P
y
t
h
o
n

Explanation:

• The loop picks each character in "Python" and prints it.

Example 4: Using for Loop with range() and step


The range() function generates a sequence of numbers, and it can take up to three
arguments: range(start, stop, step) • start (optional) The starting value (default is 0). •
stop The ending value (exclusive). • step (optional) The increment or decrement value
(default is 1).
f o r i in range ( 0 , 1 0 , 2 ) : # S t a r t = 0 , S t o p = 1 0 , S t e p =2
print ( i )

• Output:
0
2
4
6
8

Explanation:

• The loop increments i by 2 on each iteration.

Example 5: Using for Loop with break and continue


Using break (Stops the loop early)
f o r num in range ( 1 , 6 ) :
i f num == 3 :
break # Loop s t o p s a t 3
p r i n t (num)

• Output:

1
2

Using continue (Skips an iteration)


f o r num in range ( 1 , 6 ) :
i f num == 3 :
continue # S k i p s 3
p r i n t (num)

• Output:

1
2
4
5

Explanation:

• The loop skips num == 3 because of continue.

Nested for Loops (Loop Inside a Loop)


A nested for loop is a loop inside another loop. The inner loop runs completely for each
iteration of the outer loop. Syntax of Nested for Loop.

f o r o u t e r _ v a r i a b l e in o u t e r _ s e q u e n c e :
f o r i n n e r _ v a r i a b l e in i n n e r _ s e q u e n c e :
# Code b l o c k e x e c u t e d i n s i d e t h e i n n e r l o o p
54 L E C T URE 4: LOOPS: REPEATING TASKS

Example1: Multiplication Table


f o r i in range ( 1 , 4 ) : # Outer l o o p
f o r j in range ( 1 , 4 ) : # I n n e r l o o p
print ( f " { i } x { j } = { i * j } " )
print ( )
• Output:

1 x 1 = 1
1 x 2 = 2
1 x 3 = 3

2 x 1 = 2
2 x 2 = 4
2 x 3 = 6

3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
Explanation:
• The outer loop controls the row, and the inner loop controls the column.

Using else with for Loop


a for loop can have an else block. The code inside the else block executes only if the
loop completes all iterations without encountering a break statement.

f o r v a r i a b l e in sequence :
# Loop body
else :
# E x e c u t e s when t h e l o o p f i n i s h e s n o r m a l l y ( w i t h o u t b r e a k )

else in for Loop


f o r num in range ( 1 , 6 ) :
p r i n t (num)
else :
p r i n t ( " Loop completed s u c c e s s f u l l y ! " )
• Output:

1
2
3
4
5
Explanation:
• Loop completed successfully!
else with break
f o r num in range ( 1 , 6 ) :
i f num == 3 :
break # S t o p s l o o p a t 3
p r i n t (num)
else :
p r i n t ( " Loop completed s u c c e s s f u l l y ! " )
• Output:

1
2
Explanation:
• The else does not execute because the loop was terminated using break.

While Loop
The while loop is used when you want to repeat a block of code as long as a condition is
True. Unlike a for loop, where the number of iterations is known beforehand, a while
loop keeps running until the condition becomes False. Syntax of for Loop.

while c o n d i t i o n :
# Code t o e x e c u t e

• The condition is checked before each iteration.


• If the condition is True, the loop executes.
• If the condition becomes False, the loop stops.

Example 1: Using while Loop to Print Numbers


num = 1

while num <= 5 :


p r i n t (num)
num += 1 # I n c r e m e n t num
• Output:

1
2
3
4
5
Explanation:
• The loop stops when num > 5.
56 L E C T URE 4: LOOPS: REPEATING TASKS

Example 2: Using while Loop with break


num = 1

while num <= 5 :


i f num == 3 :
break # S t o p s l o o p a t 3
p r i n t (num)
num += 1

• Output:

1
2

Explanation:

• The loop stops completely when num == 3.

Example 3:Using while Loop with continue


num = 0

while num < 5 :


num += 1
i f num == 3 :
continue # Skips 3
p r i n t (num)

• Output:

1
2
4
5

Explanation:

• The loop skips printing 3.

Example 4: Using while Loop with else


num = 1

while num <= 5 :


p r i n t (num)
num += 1
else :
p r i n t ( " Loop completed s u c c e s s f u l l y ! " )

• Output:
1
2
3
4
5
Loop completed s u c c e s s f u l l y !
Explanation:
• The else executes only if the loop ends normally (without break).

Example 4:Nested while Loops (Multiplication Table)


i = 1
while i <= 3 :
j = 1
while j <= 3 :
print ( f " { i } x { j } = { i * j } " )
j += 1
print ( )
i += 1
• Output:

1 x 1 = 1
1 x 2 = 2
1 x 3 = 3

2 x 1 = 2
2 x 2 = 4
2 x 3 = 6

3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
Explanation:
• The outer loop controls the row, and the inner loop controls the column.

Summary
Loops in Python are essential for automating repetitive tasks by executing a block of code
multiple times. The two main types of loops are for loops and while loops. A for loop is
used when the number of iterations is known or when iterating over a sequence such as
a list, tuple, or string. The while loop runs as long as a specified condition remains true,
making it useful for situations where the number of iterations is unknown. Additionally,
Python provides control statements like break (to exit a loop prematurely), continue (to
skip an iteration), and pass (to define an empty loop structure). These loops enhance
code efficiency, reducing redundancy and improving readability.
In real-world applications, loops are widely used in data processing, automation, and
artificial intelligence. For example, loops help process large datasets, automate tasks
58 L E C T URE 4: LOOPS: REPEATING TASKS

like sending emails in bulk, or control game logic, such as moving characters based
on player input. They are also useful in web scraping, where a loop can extract data
from multiple pages. By mastering loops, developers can write powerful, efficient, and
scalable programs that handle repetitive tasks with minimal code.

Practice Lab:Understanding Loops in Python


Objectives
• Understand and use for and while loops in Python.

• Write programs that execute repetitive tasks efficiently.

• Implement loop control statements (break, continue).

Prerequisites
• Python installed (Download Python).

• A code editor (IDLE, VS Code, PyCharm, or Replit).

• Basic knowledge of Python syntax and conditional statements.

Lab Instructions
Step 1: Using a for Loop
# Using a f o r l o o p t o p r i n t numbers from 1 t o 5

f o r i in range ( 1 , 6 ) :
print ( i )

Step 2: Using a while Loop


# Using a w h i l e l o o p t o p r i n t numbers from 1 t o 5

num = 1
while num <= 5 :
p r i n t (num)
num += 1 # I n c r e m e n t t h e v a l u e o f num

Run the program and confirm it produces the same output as the for loop.
Step 3: Test Your Program
Break Statement
Stops the loop when a certain condition is met.
# Using b r e a k t o s t o p t h e l o o p when i == 3

f o r i in range ( 1 , 6 ) :
i f i == 3 :
break
print ( i )

Output:
1
2

Continue Statement
Skips the current iteration and moves to the next.
# Using c o n t i n u e t o s k i p number 3

f o r i in range ( 1 , 6 ) :
i f i == 3 :
continue
print ( i )

Output:
1
2
4
5

Step 4: Writing a Loop-Based Program (Challenge)


Problem: Write a program that asks the user for a number and prints the multiplication
table for that number up to 10.
Example:
E n t e r a number : 3
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
...
3 x 1 0 = 30

Solution:
# M u l t i p l i c a t i o n t a b l e using a f o r loop

num = i n t ( input ( " E n t e r a number : " ) )

f o r i in range ( 1 , 1 1 ) :
p r i n t ( f " {num} x { i } = {num * i } " )

Practice Questions
1. Write a Python program using a while loop to print numbers from 10 to 1 in reverse
order.
60 L E C T URE 4: LOOPS: REPEATING TASKS

2. Write a program that prints only odd numbers from 1 to 15 using a while loop.

3. Create a while loop that keeps asking the user for a number until they enter 0.

4. Write a program using a while loop to find the factorial of a given number.

5. Print the Fibonacci series up to 10 terms using a while loop.

6. Write a program that prints numbers from 1 to 10, but stops when it reaches 5
using break.

7. Modify the above program to skip number 5 instead of stopping, using continue.

8. Write a program that asks the user to enter numbers, but stops when the user
enters a negative number.

9. Use a loop to print numbers from 1 to 20, but skip multiples of 3 using continue.

10. Write a program that prints all numbers from 1 to 50, but stops if the number is
divisible by 13.
Lecture 5: Arrays: Indexing Variables

Introdution
In Python, arrays are used to store multiple values in a single variable. Python does not
have built-in arrays like other languages (e.g., C, Java), but it provides similar functionality
using lists or the array module.

Difference Between Lists and Arrays


Feature List ExArray (array module)
Data Type Can store different types Stores only one data type
Performance Slower for large data Faster for numerical operations
Memory Usage Uses more memory Uses less memory
Module Needed No module required Requires import array
• Use a list when you need flexibility (different data types).
• Use an array when you need efficient numerical operations.

3.Creating an Array
Using Lists (Array-like Behavior)
numbers = [ 1 0 , 2 0 , 3 0 , 4 0 , 5 0 ] # A l i s t b e h a v e s l i k e an a r r a y
p r i n t ( numbers )

• Output:
[ 1 0 , 20 , 30 , 40 , 50]

• Lists can store mixed data types, but arrays require the same type.
Using the array Module (Real Arrays in Python)
import a r r a y

numbers = a r r a y . a r r a y ( ’ i ’ , [ 1 0 , 2 0 , 3 0 , 4 0 , 5 0 ] ) # ’ i ’ means i n t e g e r a r r a y
p r i n t ( numbers )

• Output:
array ( ’ i ’ , [ 1 0 , 20 , 30 , 40 , 5 0 ] )

• The ’i’ means the array stores integers only.


• Other types: ’f’ for floats, ’d’ for double, etc.
62 L E C T URE 5: ARRAYS: INDEXING VARIABLES

4.Accessing Elements in an Array (Indexing)


Positive Indexing (Left to Right)
Index 0 1 2 3 4
value 10 20 30 40 50
numbers = [ 1 0 , 2 0 , 3 0 , 4 0 , 5 0 ]

p r i n t ( numbers [ 0 ] ) # F i r s t element
p r i n t ( numbers [ 2 ] ) # Third element
p r i n t ( numbers [ 4 ] ) # Last element

• Output:

10
30
50

Negative Indexing (Right to Left)


Index -5 -4 -3 -2 -1
value 10 20 30 40 50
numbers = [ 1 0 , 2 0 , 3 0 , 4 0 , 5 0 ]

p r i n t ( numbers [ − 1 ] ) # Last element


p r i n t ( numbers [ − 3 ] ) # Third−l a s t e l e m e n t
p r i n t ( numbers [ − 5 ] ) # F i r s t element

• Output:

50
30
10

Modifying an Array (Changing Values)


Using Lists (Array-like Behavior)
numbers = [ 1 0 , 2 0 , 3 0 , 4 0 , 5 0 ]
numbers [ 2 ] = 1 0 0 # Changing t h e v a l u e a t i n d e x 2
p r i n t ( numbers )

• Output:

[ 1 0 , 20 , 100 , 40 , 50]

• The third element (30) is replaced with 100.


5.Adding and Removing Elements
Adding Elements
numbers = [ 1 0 , 2 0 , 3 0 ]

numbers . append ( 4 0 ) # Adds 40 a t t h e end


numbers . i n s e r t ( 1 , 1 5 ) # I n s e r t s 1 5 a t i n d e x 1
p r i n t ( numbers )

• Output:

[ 1 0 , 15 , 20 , 30 , 40]

• append() adds an element at the end.

• insert(index, value) inserts a value at a specific position.

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

numbers . pop ( 2 ) # Removes e l e m e n t a t i n d e x 2


numbers . remove ( 1 0 ) # Removes t h e f i r s t o c c u r r e n c e o f 1 0
p r i n t ( numbers )

• Output:

[20 , 40 , 50]

• pop(index) removes an element at a specific position.

• remove(value) removes the first occurrence of a value.

Slicing Arrays (Extracting Portions)


Slicing allows extracting parts of an array.

The s y n t a x i s : a r r a y [ s t a r t : s t o p : s t e p ]

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

p r i n t ( numbers [ 1 : 4 ] ) # E l e m e n t s from i n d e x 1 t o 3
p r i n t ( numbers [ : 3 ] ) # F i r s t 3 elements
p r i n t ( numbers [ 3 : ] ) # From i n d e x 3 t o t h e end
p r i n t ( numbers [ : : 2 ] ) # Every second element
p r i n t ( numbers [ : : − 1 ] ) # Reverse the array

• Output:
64 L E C T URE 5: ARRAYS: INDEXING VARIABLES

[20 , 30 , 40]
[10 , 20 , 30]
[40 , 50 , 60]
[10 , 30 , 50]
[60 , 50 , 40 , 30 , 20 , 1 0 ]

::-1 is a shortcut to reverse the array.

Looping Through an Array


Using a for Loop
numbers = [ 1 0 , 2 0 , 3 0 , 4 0 , 5 0 ]

f o r num in numbers :
p r i n t (num)

• Output:

10
20
30
40
50
Using Indexes in a for Loop
numbers = [ 1 0 , 2 0 , 3 0 , 4 0 , 5 0 ]

f o r i in range ( len ( numbers ) ) :


p r i n t ( f " Index { i } : { numbers [ i ] } " )

• Output:

Index 0: 10
Index 1: 20
Index 2: 30
Index 3: 40
Index 4: 50

• len(numbers) gives the total number of elements.

Finding the Length of an Array


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

p r i n t ( len ( numbers ) ) # Get t h e number o f e l e m e n t s


• Output:

• The len() function counts elements in the array.


Sorting an Array
numbers = [ 5 0 , 1 0 , 4 0 , 2 0 , 3 0 ]

numbers . s o r t ( ) # So rt in ascending order


p r i n t ( numbers )

numbers . s o r t ( r e v e r s e = True ) # So rt in descending order


p r i n t ( numbers )

• Output:

[ 1 0 , 20 , 30 , 40 , 50]
[50 , 40 , 30 , 20 , 1 0 ]

• sort() arranges elements in ascending order.

• sort(reverse=True) arranges elements in descending order.

Sorting Using sort() Method (Modifies Original List)

• sort() sorts the list in place, meaning it changes the original list.

Ascending Order (Default)


numbers = [ 5 0 , 1 0 , 4 0 , 2 0 , 3 0 ]
numbers . s o r t ( ) # S o r t i n a s c e n d i n g o r d e r
p r i n t ( numbers )

• Output:

[ 1 0 , 20 , 30 , 40 , 50]

Descending Order (reverse=True)


numbers = [ 5 0 , 1 0 , 4 0 , 2 0 , 3 0 ]
numbers . s o r t ( r e v e r s e = True ) # S o r t i n d e s c e n d i n g o r d e r
p r i n t ( numbers )

• Output:

[50 , 40 , 30 , 20 , 1 0 ]

• reverse=True sorts the list in descending order.

• Sorting Using sorted() Function (Returns a New List)

• Unlike sort(), the sorted() function does not modify the original list; it returns a
new sorted list.

Ascending Order
66 L E C T URE 5: ARRAYS: INDEXING VARIABLES

numbers = [ 5 0 , 1 0 , 4 0 , 2 0 , 3 0 ]
sorted_numbers = s o r t e d ( numbers ) # R e t u r n s a new s o r t e d l i s t
p r i n t ( sorted_numbers )
p r i n t ( numbers ) # O r i g i n a l l i s t remains unchanged

• Output:

[ 1 0 , 20 , 30 , 40 , 50]
[50 , 10 , 40 , 20 , 30] # Original l i s t i s unchanged

Descending Order
numbers = [ 5 0 , 1 0 , 4 0 , 2 0 , 3 0 ]
sorted_numbers = s o r t e d ( numbers , r e v e r s e = True )
p r i n t ( sorted_numbers )

• Output:

[50 , 40 , 30 , 20 , 1 0 ]

• Use reverse=True to sort in descending order.

• Sorting an Array of Strings

Python sorts strings alphabetically (A-Z).


words = [ " a p p l e " , " banana " , " c h e r r y " , " d a t e " ]
words . s o r t ( ) # A l p h a b e t i c a l o r d e r
p r i n t ( words )

• Output:

[ ’ a p p l e ’ , ’ banana ’ , ’ c h e r r y ’ , ’ d a t e ’ ]

• Sorting in Reverse Order

words . s o r t ( r e v e r s e = True )
p r i n t ( words )

• Output:

[ ’ d a t e ’ , ’ c h e r r y ’ , ’ banana ’ , ’ a p p l e ’ ]

• Strings are sorted in lexicographical order (dictionary order).

• Sorting with Custom Criteria (key parameter)


words = [ " a p p l e " , " banana " , " k i w i " , " c h e r r y " ]
words . s o r t ( key = len ) # S o r t by s t r i n g l e n g t h
p r i n t ( words )

• Output:

[ ’ k i w i ’ , ’ a p p l e ’ , ’ c h e r r y ’ , ’ banana ’ ]

• The key=len sorts based on word length.


Sorting with a Custom Function
• Sorting numbers based on their remainder when divided by 10.
numbers = [ 2 3 , 4 5 , 1 2 , 6 7 , 3 4 ]
numbers . s o r t ( key =lambda x : x % 1 0 ) # S o r t by l a s t d i g i t
p r i n t ( numbers )

• Output:

[ 1 2 , 23 , 34 , 45 , 67]

• The lambda function sorts numbers by their last digit.


Sorting a List of Tuples (Sorting by Second Element
• Consider a list of student scores stored as (name, score).
s t u d e n t s = [ ( " A l i c e " , 8 5 ) , ( " Bob " , 7 2 ) , ( " C h a r l i e " , 9 0 ) , ( " David " , 6 5 ) ]
s t u d e n t s . s o r t ( key =lambda s t u d e n t : s t u d e n t [ 1 ] ) # S o r t by s c o r e s
print ( students )

• Output:

[ ( ’ David ’ , 6 5 ) , ( ’ Bob ’ , 7 2 ) , ( ’ A l i c e ’ , 8 5 ) , ( ’ C h a r l i e ’ , 9 0 ) ]

• The lambda function sorts numbers by their last digit.

Summary
Arrays are data structures used to store multiple values in a single variable, making
data manipulation more efficient. In Python, lists serve as dynamic arrays that support
various data types. Each element in an array is assigned an index, starting from 0 for the
first element, 1 for the second, and so on. Python also allows negative indexing, where -1
represents the last element, -2 the second last, and so forth. This indexing system makes
it easy to access, modify, and retrieve elements efficiently.
Indexing is particularly useful when working with loops to iterate over arrays. Using
a for loop with range(len(array)), elements can be accessed by their index for operations
such as searching, updating, or sorting. Additionally, Python provides list slicing (ar-
ray[start:end]), which enables extracting specific portions of an array. This functionality
enhances flexibility, allowing programmers to efficiently manipulate data structures and
perform various operations on stored elements.
68 L E C T URE 5: ARRAYS: INDEXING VARIABLES

Practice Lab: Writing and Running about if satatements


in Python Program
Objectives
• This lab will help you understand how to create, access, modify, and manipulate
arrays (lists) in Python using indexing, slicing, loops, and built-in functions.
Prerequisites
• Basic understanding of Python syntax

• Familiarity with loops and conditional statements.


Lab Instructions

• Step 1: Creating an Array

Lists in Python use zero-based indexing, meaning the first element is at index 0.
-Task 2: Access and print the first and last elements.
p r i n t ( " F i r s t element : " , numbers [ 0 ] )
p r i n t ( " L a s t element : " , numbers [ − 1 ] ) # Negative indexing

• Step 3: Modifying List Elements

Lists are mutable, meaning you can change their elements.


-Task 3: Modify the second element and print the updated list.
numbers [ 1 ] = 25 # Change t h e s e c o n d e l e m e n t
p r i n t ( " Updated l i s t : " , numbers )

• Step 4: Using Loops to Iterate Through an Array

You can use loops to access and manipulate list elements.


-Task 4: Print each element using a for loop.
f o r num in numbers :
p r i n t (num)

-Task 5: Print each element along with its index.


f o r i in range ( len ( numbers ) ) :
p r i n t ( f " Index { i } : { numbers [ i ] } " )

• Step 5: Slicing Lists

List slicing allows you to extract a subset of elements. -Task 6: Print a slice of the list
(first three elements).
p r i n t ( " F i r s t t h r e e e l e m e n t s : " , numbers [ : 3 ] )

• Step 5: Slicing Lists


List slicing allows you to extract a subset of elements. -Task 6: Print a slice of the list
(first three elements).
p r i n t ( " F i r s t t h r e e e l e m e n t s : " , numbers [ : 3 ] )

• Step 6: List Methods

Python lists have several built-in methods for manipulation. -Task 7: Add an element to
the list and remove an element.
numbers . append ( 6 0 ) # Add e l e m e n t a t t h e end
p r i n t ( " A f t e r appending 6 0 : " , numbers )
numbers . remove ( 3 0 ) # Remove s p e c i f i c e l e m e n t
p r i n t ( " A f t e r removing 3 0 : " , numbers )

-Task 8:Sort the list in ascending order.


numbers . s o r t ( )
p r i n t ( " S o r t e d l i s t : " , numbers )

• Step 7: Searching in a List

You can check if an element exists in a list using the in keyword. -Task 9: Check if a
number exists in the list.
i f 40 in numbers :
p r i n t ( " 40 i s i n t h e l i s t " )
else :
p r i n t ( " 40 i s not i n t h e l i s t " )

• Step 8: Reversing a List

-Task 10: CReverse the list and print it.


numbers . r e v e r s e ( )
p r i n t ( " R e v e r s e d l i s t : " , numbers )

• Step 9: Multi-Dimensional Lists

Python allows lists within lists (nested lists) to create multi-dimensional arrays. -Task 11:
Create and access a 2D list.
matrix = [
[1 , 2 , 3] ,
[4 , 5 , 6] ,
[7 , 8 , 9] ]
p r i n t ( " Element a t row 2 , column 3 : " , m a t r i x [ 1 ] [ 2 ] )
70 L E C T URE 5: ARRAYS: INDEXING VARIABLES

Practice Questions
1. Use negative indexing to print the last element of the list: colors = ["red",
"blue", "green", "yellow"].

2. Write a for loop to print all elements of the list: names = ["Alice", "Bob",
"Charlie", "David"].

3. Use a while loop to print each element in the list: ages = [18, 21, 25, 30]
until you reach an age greater than 25.

4. Given the list data = [5, 10, 15, 20, 25, 30, 35], use slicing to print the
first three elements.

5. Modify the third element of the list: scores = [90, 85, 78, 88] to 80 and print
the updated list.

6. Use list slicing to create a new list subset from: numbers = [2, 4, 6, 8, 10,
12] containing only [6, 8, 10].

7. Write a Python program that finds and prints the largest element in: values =
[12, 45, 67, 89, 23] using a loop.

8. Create a list: words = ["Python", "Java", "C++", "JavaScript"]. Use a loop


to print each word and its length.

9. Reverse the list: letters = ["a", "b", "c", "d", "e"] using slicing and print
the result.

10. Use a loop to count how many times the number 5 appears in: nums = [1, 5, 7,
5, 9, 5, 3].
Lecture 6: Functions: Better Organize Your
Code

Introduction
A function in Python is a reusable block of code that performs a specific task. Functions
help organize code, reduce redundancy, and improve readability.

Advantages of Using Functions


• Reusability Write code once and reuse it multiple times.

• Modularity Break down large programs into smaller, manageable parts.

• Improved Readability Code is easier to understand.

• Easier Debugging Fix errors in one place instead of multiple places.

Defining and Calling a Function


A function is defined using the def keyword, followed by a function name and parentheses
().

• Syntax

de f function_name ( ) :
# F u n c t i o n body ( s t a t e m e n t s )
p r i n t ( " H e l l o from t h e f u n c t i o n ! " )

• Example

de f g r e e t ( ) :
p r i n t ( " H e l l o ! Welcome t o Python . " )

# Calling the function


greet ()

• Output:

H e l l o ! Welcome t o Python .

• The function greet() is defined once, but it can be called multiple times.
72 L E C T URE 6: FUNCTIONS: BET TER ORGANIZE YOUR CODE

Function with Parameters (Passing Arguments)


A function can accept values (called parameters) to perform operations on them.

• Function with Parameters

de f g r e e t ( name ) :
p r i n t ( f " H e l l o , { name } ! " )

# C a l l i n g f u n c t i o n with d i f f e r e n t v a l u e s
greet ( " Alice " )
g r e e t ( " Bob " )

• Output:

Hello , A l i c e !
H e l l o , Bob !

• Here, name is a parameter inside the function definition.

• "Alice" and "Bob" are arguments passed when calling the function.

Function with Multiple Parameters


A function can accept multiple parameters.

• Function with Parameters

de f add_numbers ( a , b ) :
result = a + b
p r i n t ( f " The sum o f { a } and { b } i s { r e s u l t } " )

# Calling the function


add_numbers ( 5 , 1 0 )
add_numbers ( 2 0 , 3 0 )

• Output:

The sum o f 5 and 1 0 i s 1 5


The sum o f 20 and 30 i s 50

• The function takes two parameters, a and b, and prints their sum.
Function with Return Value
A function can return a value using the return statement.

• Function with Return Value

de f m u l t i p l y ( a , b ) :
return a * b # R e t u r n i n g t h e m u l t i p l i c a t i o n r e s u l t

# C a l l i n g f u n c t i o n and s t o r i n g t h e r e s u l t
result = multiply (4 , 5)
print ( " Multiplication Result : " , r e s u l t )

• Output:

M u l t i p l i c a t i o n R e s u l t : 20

• The function returns a value instead of printing it directly.

• The returned value can be stored in a variable for further use.

6.Function with Keyword Arguments (kwargs)


Python allows you to pass arguments by keywords (named arguments).

• Example

de f i n t r o d u c e ( name , age ) :
p r i n t ( f "My name i s { name } and I am { age } y e a r s o l d . " )

# C a l l i n g f u n c t i o n u s i n g keyword arguments
i n t r o d u c e ( age = 2 5 , name= " John " )

• Output:

My name i s John and I am 25 y e a r s o l d .

• Using keyword arguments, the order of parameters doesn’t matter.


74 L E C T URE 6: FUNCTIONS: BET TER ORGANIZE YOUR CODE

Arbitrary Arguments (*args and **kwargs)


• Use *args to pass multiple positional arguments.
• Use **kwargs to pass multiple keyword arguments.
• Using *args
de f a d d _ a l l ( * numbers ) :
return sum ( numbers )

print ( add_all ( 1 , 2 , 3 , 4 , 5 ) ) # Passing multiple values

• Output:
15

• *args allows passing any number of arguments.


• Using **kwargs
de f p r i n t _ i n f o ( * * i n f o ) :
f o r key , v a l u e in i n f o . i t e m s ( ) :
p r i n t ( f " { key } : { v a l u e } " )

p r i n t _ i n f o ( name= " A l i c e " , age = 2 5 , c i t y = "New York " )

• Output:
name : A l i c e
age : 25
c i t y : New York

• **kwargs allows passing multiple named arguments.

Recursive Functions (Function Calling Itself )


A function can call itself recursively.
• Factorial Using Recursion
de f f a c t o r i a l ( n ) :
i f n == 0 or n == 1 : # Base c a s e
return 1
else :
return n * f a c t o r i a l ( n − 1 ) # R e c u r s i v e c a l l

print ( f a c t o r i a l ( 5 ) )

• Output:
120

• Recursion is useful for problems like factorials, Fibonacci series, and tree struc-
tures.
Lambda Functions (Anonymous Functions)
A lambda function is a small anonymous function.

• Example

de f f a c t o r i a l ( n ) :
# Regular function
de f s q u a r e ( x ) :
return x * x

# Lambda f u n c t i o n ( s h o r t e r s y n t a x )
square_lambda = lambda x : x * x

print ( square ( 5 ) ) # Using r e g u l a r f u n c t i o n


p r i n t ( square_lambda ( 5 ) ) # Using lambda f u n c t i o n

• Output:

25
25

• Use lambda functions for small, one-line operations.

Summary
In Python, a function is a reusable block of code that performs a specific task. Functions
help in organizing code, improving readability, and reducing redundancy. They are de-
fined using the ’def’ keyword followed by a function name and parentheses. Parameters
can be passed to functions, and they can return values after execution.
Functions can be of different types, including built-in functions (like print(), len())
and user-defined functions. Python also supports lambda (anonymous) functions, recur-
sive functions, and higher-order functions. Using functions effectively enhances code
modularity and maintainability.
Functions can also have default parameter values, allowing flexibility in function
calls. They can accept an arbitrary number of arguments using *args (for positional
arguments) and **kwargs (for keyword arguments). Additionally, Python allows function
nesting and closures, which are useful for encapsulating logic. Properly documenting
and structuring functions ensures better readability and reusability in programming.

Practice Lab: Writing and Running about if satatements


in Python Program
Objectives

• This lab will help you understand how to create, access, modify, and manipulate
arrays (lists) in Python using indexing, slicing, loops, and built-in functions.
76 L E C T URE 6: FUNCTIONS: BET TER ORGANIZE YOUR CODE

Prerequisites

• Learn how to define and call functions in Python.

• Understand different function types, including built-in, user-defined, lambda, and


recursive functions.

• Explore function arguments, return values, and scope.

• Practice writing efficient and reusable code using functions.

Lab Instructions

• Tasks

Task 1: Basic Function Definition and Calling.

• Define a function that prints Welcome to the Python Practice Lab.

• Call the function to display the message.

Task 2: Function with Parameters and Return Value

• Write a function squarenumber that returns the square of a given number.

• Test it by printing squarenumber(5).

Task 3: Function with Default Arguments

• Create a function ‘greet(name="Guest")‘ that prints "Hello, [name]!" with "Guest"


as the default value

• Call ‘greet()‘ and ‘greet("Alice")‘ to observe the behavior.

Task 4: Lambda Function

• Define a lambda function ‘multiply = lambda x, y: x * y

• Use it to multiply two numbers and print the result.

Task 5: Recursive Function

• Implement a function ‘factorial(n)‘ that calculates the factorial of a number using


recursion.

• Call ‘factorial(5)‘ and print the result.


Practice Questions
1. Create a function find_max(*args) that returns the maximum number from an
arbitrary number of arguments.

2. Write a function palindrome(s) that checks if a string is a palindrome (reads the


same forward and backward).

3. Implement a function factorial(n) that returns the factorial of a given number


using recursion.

4. Write a function fibonacci(n) that returns the nth Fibonacci number using re-
cursion.

5. Define a function sort_dict_by_value(d, reverse=False) that sorts a dictio-


nary by its values.

6. Define a function apply_function(func, values) that applies a given function


to each element in a list.

7. Write a function is_prime(n) that checks if a number is prime.

8. Create a higher-order function operate(func, a, b) that takes another function


as an argument and applies it to two numbers.

9. Implement a function decorator_example(func) that demonstrates the use of


decorators in Python.

10. Write a function count_words(filename) that reads a file and returns the count
of each word.
78 L E C T URE 6: FUNCTIONS: BET TER ORGANIZE YOUR CODE
Lecture 7: External Packages and Modules

Python packages are a core element of the language’s ecosystem. They serve as containers
for modules, scripts, and data that work together to provide reusable functionality. A
package is essentially a directory that contains a collection of Python modules along
with an optional __init__.py file. This file signals to Python that the directory should be
treated as a package, allowing the modules inside it to be imported using dot notation.
The modular nature of packages promotes organization, maintainability, and code reuse.
Instead of reinventing the wheel, developers can import functionality from established
packages, streamlining the development process and improving code reliability.
Python packages fulfill several important roles. First, they encourage a clean sepa-
ration of concerns by allowing developers to group related functionality together. This
means that when building complex applications, one can separate data processing logic,
user interface components, and business rules into distinct packages. Second, packages
serve as a mechanism for distributing and sharing code. Many open-source libraries
are available as packages that can be installed and integrated into projects, thereby
empowering developers to leverage the work of others. Third, packages enable easier
testing and debugging by allowing developers to isolate functionality into smaller, more
manageable units. The result is a more modular and scalable codebase.

Purpose of Python Packages


The primary purpose of Python packages is to provide a structured way to organize
code. When you write a program that grows in complexity, it becomes essential to
manage multiple files and modules effectively. Packages allow you to logically group
code together so that related functionality is contained in one place. This modularity
makes it easier to maintain the code over time because any updates or bug fixes can be
implemented in isolated modules without affecting unrelated parts of the application.
Another significant purpose is to promote code reuse. With Python packages, devel-
opers can create libraries that encapsulate common tasks—such as data manipulation,
file handling, web requests, or even complex scientific computations—and then reuse
these libraries across multiple projects. For instance, the NumPy package offers effi-
cient array operations and mathematical functions, while Pandas provides powerful
data structures and data analysis tools. These packages are used extensively not only in
academic research and data science but also in industrial applications. Reusing such
packages reduces development time and increases reliability, as these libraries are often
well-tested and continuously maintained by a vibrant community.
Furthermore, packages are designed to facilitate collaboration among developers. By
following standardized naming conventions and directory structures, Python packages
provide a common ground for sharing and integrating code. This standardization is
especially beneficial in open-source projects, where multiple contributors can work on
80 L E C T URE 7: EXTERNAL PACKAGES AND MODULES

different parts of the codebase while ensuring consistency and compatibility. The clear
separation of modules into packages also simplifies the process of writing documentation
and tutorials, making it easier for newcomers to understand how to use the available
tools.

Examples of Using Python Packages


One of the most common examples of Python packages in action is seen in data analysis.
Consider the Pandas package, which is widely used for manipulating and analyzing
structured data. When working with a dataset, a developer might import Pandas to load
data from a CSV file, perform data cleaning, and run statistical analyses. A typical script
might look like this:
import pandas a s pd

# Load data from a CSV f i l e


d a t a = pd . r e a d _ c s v ( " d a t a . c s v " )

# Display the f i r s t f i v e rows o f t h e d a t a s e t


p r i n t ( d a t a . head ( ) )

# Compute b a s i c s t a t i s t i c s f o r t h e d a t a s e t
s t a t i s t i c s = data . describe ( )
print ( s t a t i s t i c s )
In this example, Pandas is a package that provides a module (pd) with functions like
read_csv and describe. The package encapsulates a rich set of functionalities that enable
efficient data manipulation without requiring the developer to write low-level code.
Please note that a file named data.csv is a common example used to represent a
CSV (Comma-Separated Values) file. CSV files are plain text files that store tabular data,
where each line of the file represents a row of data, and each row is divided into fields
(or columns) separated by commas. This simple format makes CSV files easy to create,
read, and import into various programs such as spreadsheet software (e.g., Microsoft
Excel, Google Sheets), databases, and programming languages like Python.
A CSV file typically starts with a header row that defines the names of the columns,
followed by rows containing the data. Here’s an example of what the content of a data.csv
file might look like:
Name , Age , C i t y
A l i c e , 3 0 , New York
Bob , 2 5 , Los A n g e l e s
C h a r l i e , 3 5 , Chicago
Another example is in web development. Frameworks like Django and Flask are
built as packages. Django, a high-level web framework, provides a complete solution
for building robust web applications. It includes modules for handling HTTP requests,
interacting with databases, templating for dynamic web pages, and much more. A small
snippet of a Django view might look like this:
from django . h t t p import HttpResponse

de f home ( r e q u e s t ) :
return HttpResponse ( " Welcome t o my w e b s i t e ! " )
Here, the Django package abstracts the complexity of web protocols and server
management, allowing developers to focus on the application logic.
Packages are also central to scientific computing. The SciPy package, for example,
builds on NumPy to offer advanced mathematical functions, optimizers, and statistical
routines. A researcher might use SciPy to solve a differential equation numerically,
thereby leveraging a library that has been optimized for performance and accuracy.

pip: The Python Package Installer


Central to the ease of using Python packages is pip, the Python Package Installer. Pip is
the standard tool for installing and managing packages from the Python Package Index
(PyPI), which is the largest repository of Python software. With a simple command-line
interface, pip allows developers to quickly add external packages to their projects.
Installing a package with pip is straightforward. For instance, to install the Requests
package—a popular library for making HTTP requests—you would open your terminal
or command prompt and type:
pip i n s t a l l r e q u e s t s

This command connects to PyPI, downloads the latest version of the package, and
installs it on your system. Pip also handles dependencies, meaning that if a package
requires other packages to function correctly, pip will install those as well.
Pip supports additional features that streamline project management. Developers can
create a requirements.txt file that lists all the packages and specific versions needed for
a project. This file makes it easy to set up the same environment on different machines
by running:
pip i n s t a l l −r r e q u i r e m e n t s . t x t

Moreover, pip provides commands to upgrade packages (pip install –upgrade pack-
age_name), uninstall packages (pip uninstall package_name), and even search for pack-
ages on PyPI (pip search keyword). These features make pip an essential tool for Python
developers, ensuring that they have access to the latest and most secure versions of the
packages they rely on.
A requirements.txt file is a plain text file used to list all the external Python packages
that your project depends on. Each line in the file specifies a package, optionally with a
version number or range to ensure consistency across different environments. This file
makes it easy for others (or for deployment processes) to install the exact versions of the
dependencies your project needs.
Here’s an example of what a requirements.txt file might look like:
# T h i s i s a sample r e q u i r e m e n t s . t x t f i l e f o r a Python p r o j e c t

# S p e c i f y a package with an e x a c t v e r s i o n
Django = = 3 . 2 . 5

# S p e c i f y a package with a minimum v e r s i o n ( and no upper l i m i t )


requests > = 2 . 2 5 . 1

# S p e c i f y a package with an e x a c t v e r s i o n
numpy = = 1 . 2 1 . 0
82 L E C T URE 7: EXTERNAL PACKAGES AND MODULES

# S p e c i f y a package with a v e r s i o n r a n g e
pandas > = 1 . 3 . 0 , < 1 . 4 . 0

# You can a l s o l i s t p a c k a g e s w i t h o u t v e r s i o n s p e c i f i e r s i f you want t h e l a t e s t v e r s i o n


scipy

Explanation

• Comments: Lines starting with # are comments and are ignored by pip. Use them
to explain sections of your file or add context for certain dependencies.

• Exact Version: Django==3.2.5 tells pip to install version 3.2.5 of Django exactly. This
ensures that everyone working on the project uses the same version.

• Minimum Version: requests>=2.25.1 specifies that pip should install version 2.25.1
or higher of the requests package, which provides some flexibility while ensuring
that features introduced in that version are available.

• Version Range: pandas>=1.3.0,<1.4.0 indicates that pandas should be at least version


1.3.0 but less than 1.4.0. This is useful when you know a major version update might
introduce breaking changes.

• No Version Specified: Listing a package like scipy without a version tells pip to
install the latest available version, which can be useful during rapid development
but may lead to inconsistencies if newer versions introduce changes.

Example of Popular Python Packages


In this discussion, we will focus on several prominent packages: NumPy, Pandas, Mat-
plotlib, Requests, and a brief look at web development frameworks such as Django and
Flask. Each section will explain the purpose of the package, highlight its major features,
and provide code examples that illustrate typical usage patterns.

NumPy: Numerical Computing Made Efficient


NumPy is the foundational package for numerical computing in Python. It provides
support for large, multi-dimensional arrays and matrices, along with a wide array of
mathematical functions to operate on these data structures efficiently. NumPy’s perfor-
mance and ease of use make it an essential tool for scientific computing, data analysis,
and machine learning.
Key Features

• N-Dimensional Array Object: The primary data structure in NumPy is the ndarray,
which can represent arrays of any dimensionality.

• Broadcasting: Allows arithmetic operations on arrays of different shapes.

• Mathematical Functions: Optimized functions for operations like linear algebra,


Fourier transforms, and statistics.
• Integration: Works seamlessly with many other Python packages that rely on nu-
merical computations.

Below is a simple example that demonstrates how to create an array, perform arith-
metic operations, and compute basic statistics using NumPy:
import numpy a s np

# C r e a t e a NumPy a r r a y from a Python l i s t .


d a t a = np . a r r a y ( [ 1 , 2 , 3 , 4 , 5 ] )
print ( " O r i g i n a l array : " , data )

# Perform a r i t h m e t i c o p e r a t i o n s .
squared = d a t a * * 2
p r i n t ( " Squared v a l u e s : " , squared )

# Compute t h e mean and s t a n d a r d d e v i a t i o n .


mean_value = np . mean ( d a t a )
s t d _ d e v i a t i o n = np . s t d ( d a t a )
p r i n t ( "Mean : " , mean_value )
print ( " Standard Deviation : " , s t d _ d e v i a t i o n )

In this example, NumPy is used to quickly compute the square of each element, as
well as to calculate the mean and standard deviation of the array. These operations,
which might be slow in pure Python for large datasets, are highly optimized in NumPy.

Pandas: Data Analysis and Manipulation


Pandas is a powerful data manipulation and analysis library built on top of NumPy. It
introduces two primary data structures: Series (one-dimensional) and DataFrame (two-
dimensional), which allow you to work with labeled data easily. Pandas is widely used
for data cleaning, transformation, and analysis, making it a go-to tool in data science
and business analytics.
Key Features

• DataFrame: A two-dimensional table with rows and columns, similar to a spread-


sheet.

• Handling Missing Data: Functions for detecting, removing, or filling missing values.

• Data Alignment: Automatic alignment of data for time series and other complex
datasets.

• Integration with Other Tools: Works well with visualization libraries and machine
learning frameworks.

Consider a CSV file containing employee data. Using Pandas, you can load, inspect,
and analyze this data as follows:
import pandas a s pd

# Read data from a CSV f i l e i n t o a DataFrame .


d f = pd . r e a d _ c s v ( ’ employees . c s v ’ )
84 L E C T URE 7: EXTERNAL PACKAGES AND MODULES

# D i s p l a y t h e f i r s t few rows o f t h e DataFrame .


p r i n t ( " Data p r e v i e w : " )
p r i n t ( d f . head ( ) )

# F i l t e r t h e DataFrame t o f i n d e m p l o y e e s i n a s p e c i f i c department .
e n g i n e e r i n g = d f [ d f [ ’ Department ’ ] == ’ E n g i n e e r i n g ’ ]
p r i n t ( " E n g i n e e r i n g Department : " )
print ( engineering )

# C a l c u l a t e t h e a v e r a g e s a l a r y by department .
a v e r a g e _ s a l a r y = d f . groupby ( ’ Department ’ ) [ ’ S a l a r y ’ ] . mean ( )
p r i n t ( " A v e r a g e S a l a r y by Department : " )
print ( average_salary )

In this example, Pandas is used to read a CSV file, filter the data based on specific cri-
teria, and compute statistics grouped by a categorical column. The DataFrame structure
makes it straightforward to perform these operations with minimal code.

Matplotlib: Visualizing Data


Matplotlib is one of the most popular Python libraries for data visualization. It provides
a comprehensive API for creating static, animated, and interactive plots. Whether you
need to generate simple line charts, complex bar graphs, or scatter plots, Matplotlib
offers a range of tools to visualize data clearly and effectively.
Key Features

• Plotting Functions: Support for various plot types including line, scatter, bar, his-
togram, and pie charts.

• Customization: Extensive options to customize the appearance of plots, such as


colors, markers, line styles, and labels.

• Integration: Works well with Pandas and NumPy, making it easy to visualize data
directly from arrays or DataFrames.

• Interactive Environments: Can be used in Jupyter Notebooks to display interactive


plots inline.

Below is an example that shows how to create a simple line plot using Matplotlib:
import m a t p l o t l i b . p y p l o t a s p l t
import numpy a s np

# G e n e r a t e some sample data u s i n g NumPy .


x = np . l i n s p a c e ( 0 , 1 0 , 1 0 0 )
y = np . s i n ( x )

# Create a line plot .


p l t . p l o t ( x , y , l a b e l = ’ S i n e Wave ’ , c o l o r = ’ b l u e ’ , l i n e w i d t h = 2 )

# Add t i t l e s and l a b e l s .
p l t . t i t l e ( ’ S i n e Wave Example ’ )
plt . xlabel ( ’ x values ’ )
plt . ylabel ( ’ sin ( x ) ’ )

# Display a legend .
p l t . legend ( )

# Show t h e p l o t .
p l t . show ( )

This script generates an array of x-values, computes the sine of those values, and
then plots the result as a smooth line. The plot includes labels, a title, and a legend,
making it clear and informative. Matplotlib’s flexibility allows you to fine-tune every
aspect of the plot to suit your needs.

Requests: Simplifying HTTP Requests


Requests is a popular package for handling HTTP requests in Python. It abstracts the
complexity of making HTTP calls behind a simple and intuitive API. Whether you need
to fetch data from a web API, download files, or submit form data, Requests makes it
easy to interact with web services.
Key Features

• Simple API: Intuitive methods for GET, POST, PUT, DELETE, and other HTTP
requests.

• Handling Responses: Automatically decodes JSON responses and handles status


codes.

• Session Objects: Manage and persist settings across multiple requests, such as
cookies and headers.

• Error Handling: Provides mechanisms to handle network errors gracefully.

import r e q u e s t s

# Make a GET r e q u e s t t o a p u b l i c API .


r e s p o n s e = r e q u e s t s . g e t ( ’ h t t p s : / / a p i . g i t h u b . com ’ )

# Check i f t h e r e q u e s t was s u c c e s s f u l .
i f r e s p o n s e . s t a t u s _ c o d e == 2 0 0 :
# P a r s e t h e JSON r e s p o n s e .
data = response . json ( )
p r i n t ( " GitHub API Response : " )
print ( data )
else :
p r i n t ( " F a i l e d t o r e t r i e v e d a t a . S t a t u s code : " , r e s p o n s e . s t a t u s _ c o d e )

In this example, Requests is used to fetch data from the GitHub API. The response is
checked for a successful status code before parsing the JSON data. This simple, human-
readable approach makes interacting with web services much more accessible compared
to lower-level libraries.
86 L E C T URE 7: EXTERNAL PACKAGES AND MODULES

Web Development Frameworks: Django and Flask


Python offers robust frameworks for web development, with Django and Flask being
two of the most well-known. These frameworks help developers build web applications
quickly by providing tools and libraries for common web development tasks such as
URL routing, database interaction, and templating.
Django is a high-level framework that follows the “batteries-included” philosophy. It
comes with a rich set of built-in features, including an ORM (Object-Relational Mapping)
for database operations, an admin interface, and a templating engine.
A typical Django project involves setting up models, views, and templates. Here’s a
simplified snippet from a Django view:
from django . h t t p import HttpResponse

de f home ( r e q u e s t ) :
return HttpResponse ( " Welcome t o my Django−powered w e b s i t e ! " )
In this example, the view function home returns an HTTP response with a welcome
message. Django takes care of the rest—routing the request to this view, rendering the
response, and managing the entire lifecycle of the web request.
Flask is a lightweight micro-framework that provides the essentials for web develop-
ment without the overhead of a full-stack framework like Django. It is ideal for small
applications or microservices where simplicity and flexibility are paramount.
A basic Flask application can be written in just a few lines of code:
from f l a s k import F l a s k

app = F l a s k ( __name__ )

@app . r o u t e ( ’ / ’ )
de f home ( ) :
return " H e l l o from F l a s k ! "

i f __name__ == ’ __main__ ’ :
app . run ( debug= True )
This snippet creates a Flask application, defines a route for the home page, and starts
a local development server. Flask’s minimalist approach allows you to add only the
components you need, making it a great choice for projects that require a lightweight
web framework.

Creating Your Own Package in Python


Creating your own package in Python is a powerful way to organize reusable code, share
functionality across multiple projects, and even distribute your work to the broader
Python community. In this guide, we’ll explore the process of building a Python pack-
age from scratch, covering everything from directory structure and module creation
to packaging, testing, and even preparing your package for distribution via PyPI. This
comprehensive guide is structured in several sections and includes code examples and
best practices to help you get started.
In Python, a package is essentially a directory that contains a collection of modules,
along with a special file named __init__.py. This file (which can be empty) indicates to
Figure 1: Package Structure

the Python interpreter that the directory should be treated as a package. Packages allow
you to group related functionality into a single, organized hierarchy, making your code
more maintainable and reusable. By creating your own package, you can encapsulate
utility functions, classes, and resources that you might want to use in various projects
without copying and pasting code repeatedly.
A well-organized package begins with a clear directory structure. Let’s assume you
want to create a package called mypackage. The basic directory layout might look like
this:

• Outer Directory (mypackage/): This is the root folder of your project. It contains
your package’s source code as well as configuration and documentation files.

• Inner Package Directory (mypackage/mypackage/): This folder holds the actual


package code. The presence of an __init__.py file makes this directory a Python
package. You can include multiple modules here (e.g., module1.py and module2.py)
that encapsulate different parts of your package’s functionality.

• Tests Directory (mypackage/tests/): It is a best practice to include tests that verify


your package’s functionality. The tests directory can also be a package if it contains
an __init__.py file.

• Setup Script (setup.py): This file is used by setuptools to build and distribute
your package. It includes metadata such as the package name, version, author
information, and dependencies.
88 L E C T URE 7: EXTERNAL PACKAGES AND MODULES

• README.md: A Markdown file that explains what your package does, how to
install it, and how to use it. This file is especially useful for open-source projects.

Creating the Package Files


The __init__.py file is crucial because it signals that the directory is a Python package.
This file can be empty, but it can also be used to initialize package-level variables or
import submodules. For example, you might include a version string:
# mypackage / _ _ i n i t _ _ . py
__version__ = " 0 . 1 . 0 "

You can also import key functions or classes to expose them at the package level:
# mypackage / _ _ i n i t _ _ . py
from . module1 import g r e e t
from . module2 import c a l c u l a t e

Writing Modules
Create modules that contain your package’s functionality. For instance, in module1.py,
you might define a simple greeting function:
# mypackage / module1 . py
de f g r e e t ( name ) :
"""
R e t u r n a g r e e t i n g message f o r t h e g i v e n name .
"""
return f " H e l l o , { name } ! "

In module2.py, you might include a simple calculation function:


# mypackage / module2 . py
de f c a l c u l a t e ( a , b , o p e r a t i o n = " add " ) :
"""
Perform a b a s i c a r i t h m e t i c o p e r a t i o n on two numbers .

: param a : F i r s t number .
: param b : Second number .
: param o p e r a t i o n : The o p e r a t i o n t o p e r f o r m ( " add " , " s u b t r a c t " , " m u l t i p l y " , o r " d i v i
: r e t u r n : The r e s u l t o f t h e o p e r a t i o n .
"""
i f o p e r a t i o n == " add " :
return a + b
e l i f o p e r a t i o n == " s u b t r a c t " :
return a − b
e l i f o p e r a t i o n == " m u l t i p l y " :
return a * b
e l i f o p e r a t i o n == " d i v i d e " :
i f b == 0 :
r a i s e V a l u e E r r o r ( " D i v i s i o n by z e r o i s not a l l o w e d . " )
return a / b
else :
r a i s e V a l u e E r r o r ( " Unsupported o p e r a t i o n . " )
Testing Your Package
Before distributing your package, it’s important to ensure it works as expected. Create
tests in the tests/ directory. For example, in tests/test_module1.py you could write:
# t e s t s / t e s t _ m o d u l e 1 . py
import u n i t t e s t
from mypackage . module1 import g r e e t

c l a s s TestModule1 ( u n i t t e s t . T e s t C a s e ) :
def t e s t _ g r e e t ( s e l f ) :
s e l f . a s s e r t E q u a l ( g r e e t ( " A l i c e " ) , " Hello , A l i c e ! " )
s e l f . a s s e r t E q u a l ( g r e e t ( " Bob " ) , " H e l l o , Bob ! " )

i f __name__ == ’ __main__ ’ :
u n i t t e s t . main ( )

Running your tests can be done using a test runner such as unittest or pytest. From
the command line, you could run:
python −m u n i t t e s t d i s c o v e r t e s t s

This will automatically discover and run tests in the tests directory.

Packaging for Distribution


To share your package with others or upload it to PyPI, you need a setup.py file. This file
contains metadata about your package and instructions for building it. A basic setup.py
might look like this:
# s e t u p . py
from s e t u p t o o l s import setup , f i n d _ p a c k a g e s

setup (
name= " mypackage " ,
version =" 0 . 1 . 0 " ,
d e s c r i p t i o n = "A s i m p l e Python package f o r g r e e t i n g and b a s i c a r i t h m e t i c o p e r a t i o n s . "
a u t h o r = " Your Name" ,
a u t h o r _ e m a i l = " your . email@example . com" ,
packages = find_packages ( ) , # A u t o m a t i c a l l y f i n d packages in the d i r e c t o r y .
install_requires =[] , # L i s t d e p e n d e n c i e s h e r e i f any .
c l a s s i f i e r s =[
" Programming Language : : Python : : 3 " ,
" O p e r a t i n g System : : OS Independent " ,
],
)

This script uses setuptools to package your code. The find_packages() function
automatically discovers all packages (directories with an __init__.py file) under your
project directory.
After creating setup.py, you can build a distribution package by running:
python s e t u p . py s d i s t b d i s t _ w h e e l

This command creates source and wheel distributions in a new dist/ directory. These
files can then be uploaded to PyPI using a tool like twine:
90 L E C T URE 7: EXTERNAL PACKAGES AND MODULES

pip i n s t a l l t w i n e
t w i n e upload d i s t / *

For local testing, you can install your package in editable mode using:
pip i n s t a l l −e .

This installs your package in a way that changes you make in the source files are
immediately reflected when you import your package.

Summary
Python packages are a core element of the language’s ecosystem that allow developers to
organize and reuse code efficiently. A package is essentially a directory containing one
or more modules—Python files with reusable code—and an __init__.py file that signals
to the interpreter that the directory should be treated as a package. This structure makes
it easier to logically group related functionality, maintain codebases, and share libraries
with others.
The primary purpose of packages is to facilitate modular programming. By breaking
a project into smaller, self-contained modules, developers can focus on individual com-
ponents, which promotes code reusability and simplifies debugging and maintenance.
Packages also help in avoiding naming conflicts and provide a clear hierarchy when
projects grow in complexity.
In addition to organizing code, Python packages support code distribution. Develop-
ers can bundle their packages for distribution via tools like pip—the Python Package
Installer—which connects to repositories like the Python Package Index (PyPI). Pip
simplifies the process of installing, upgrading, and managing package dependencies
through commands such as pip install package_name and the use of a requirements.txt
file, which lists all dependencies needed for a project.
Overall, Python packages are essential for building scalable, maintainable, and share-
able software. They not only streamline the development process by enabling code
reuse but also foster collaboration within the Python community through standardized
packaging and distribution practices.

Practice Lab: Creating and Using Python Packages


Objectives
• Understand the purpose and structure of Python packages.

• Create a simple package with multiple modules.

• Write code in each module and initialize the package.

• Import and use your package’s functions in a separate script.

• Run tests to verify that your package works correctly.


Figure 2: Package Structure for the Practice Lab

Prerequisites
• Python 3 installed on your computer.
• A text editor or Integrated Development Environment (IDE) (e.g., Visual Studio
Code, PyCharm, Sublime Text).
• Basic familiarity with Python (variables, functions, and file organization).
• Access to a terminal or command prompt for running scripts.

Part 1: Setting Up the Package Structure


1. Create the Directory Structure Create a new directory for your package project.
For example, create a folder named my_package_lab. Inside this folder, create the
following subdirectories and files:
• The mypackage directory will contain your package code.
• The __init__.py file indicates that mypackage is a Python package (this file
can be empty or used to expose key functions).
• The greetings.py and mathops.py files will contain simple functions.
• The tests directory is for writing tests to verify your code.
• The main.py file will be your script to import and use your package.
2. Create the __init__.py File Open mypackage /__init__.py and add the following
content to expose the functions from your modules:
92 L E C T URE 7: EXTERNAL PACKAGES AND MODULES

# mypackage / _ _ i n i t _ _ . py
from . g r e e t i n g s import g r e e t
from . mathops import add , s u b t r a c t

Part 2: Writing the Package Modules


1. Module: greetings.py Open mypackage/greetings.py and add a simple function
that returns a greeting:
# mypackage / g r e e t i n g s . py

de f g r e e t ( name ) :
"""
R e t u r n a p e r s o n a l i z e d g r e e t i n g message .
: param name : The name o f t h e p e r s o n .
: return : A greeting string .
"""
return f " H e l l o , { name } ! Welcome t o my package . "

2. Module: mathops.py Open mypackage/mathops.py and write two simple arith-


metic functions:
# mypackage / mathops . py

de f add ( a , b ) :
"""
R e t u r n t h e sum o f a and b .
: param a : F i r s t number .
: param b : Second number .
: r e t u r n : Sum o f a and b .
"""
return a + b

de f s u b t r a c t ( a , b ) :
"""
R e t u r n t h e d i f f e r e n c e o f a and b .
: param a : F i r s t number .
: param b : Second number .
: r e t u r n : D i f f e r e n c e o f a and b .
"""
return a − b

Part 3: Testing Your Package


1. Write a Test for the Greetings Module Create the file tests/test_greetings.py and
add a simple test to check if the greeting function works correctly:
# t e s t s / t e s t _ g r e e t i n g s . py
import u n i t t e s t
from mypackage . g r e e t i n g s import g r e e t

c l a s s TestGreetings ( u n i t t e s t . TestCase ) :
def t e s t _ g r e e t ( s e l f ) :
s e l f . a s s e r t E q u a l ( g r e e t ( " A l i c e " ) , " H e l l o , A l i c e ! Welcome t o my package . " )
i f __name__ == ’ __main__ ’ :
u n i t t e s t . main ( )

2. Run the Tests Open your terminal, navigate to the my_package_lab directory, and
run:
python −m u n i t t e s t d i s c o v e r t e s t s

If your test passes, you will see output indicating that everything is working as
expected.

Part 4: Using Your Package in a Script


1. Write the Main Script Open main.py and write a script that imports your package
functions and uses them:
# main . py
from mypackage import g r e e t , add , s u b t r a c t

de f main ( ) :
# Use t h e g r e e t i n g f u n c t i o n .
name = input ( " E n t e r your name : " )
p r i n t ( g r e e t ( name ) )

# Use t h e math o p e r a t i o n s .
a = f l o a t ( input ( " E n t e r t h e f i r s t number : " ) )
b = f l o a t ( input ( " E n t e r t h e second number : " ) )

p r i n t ( f " The sum o f { a } and { b } i s : { add ( a , b ) } " )


p r i n t ( f " The d i f f e r e n c e between { a } and { b } i s : { s u b t r a c t ( a , b ) } " )

i f __name__ == " __main__ " :


main ( )

2. Run the Main Script In your terminal, ensure you are in the my_package_lab
directory and run:
python main . py

Follow the on-screen prompts to test the functionality of your package.

Part 5: Reflection and Exploration


1. Reflect on the Package Structure: Consider how separating functionality into dif-
ferent modules (greetings.py and mathops.py) and organizing them under the
mypackage directory improves code readability and maintainability.

2. Experiment with __init__.py: Try modifying mypackage/__init__.py to import ad-


ditional functions or to add package-level variables. Observe how these changes
affect the way you import functions in your main.py.
94 L E C T URE 7: EXTERNAL PACKAGES AND MODULES

3. Extend the Package: Add another module (e.g., datetime_ops.py) that provides
functions related to date and time manipulation. Update the __init__.py file and
test your new functionality in main.py.
4. Test Thoroughly: Write more unit tests for the other modules in your package to
ensure all functions work as expected.

Practice Questions
1. What is a Python package and how does it differ from a Python module?
2. Why is the __init__.py file important in a package?
3. Draw or describe the directory structure of a simple Python package named my-
package that contains two modules (module1.py and module2.py) and a tests
directory for unit tests.
4. What would happen if you omitted the __init__.py file from your package directo-
ries?
5. Write an example of how you would import a function named my_function from
module1.py in your mypackage package.
6. How can you import multiple modules or functions from a package in a single
line?
7. Create a small package called mathutils that contains a module operations.py with
a function add(a, b) which returns the sum of a and b. Then write a script that
imports add from mathutils.operations and uses it to add two numbers.
8. Describe the steps and files needed to convert a collection of related modules into
a package.
9. How do you install an external package (for example, requests) using pip?
10. What is a requirements.txt file and how would you use it to manage package
dependencies in your project?
11. Write a sample requirements.txt file that specifies at least three packages with
version constraints.
12. Explain the purpose of the setup.py file in a Python package.
13. Outline the steps required to package your own Python package for distribution
on PyPI.
14. What command would you use to build a source distribution of your package?
15. Which command can you use to list all the Python packages currently installed in
your environment using pip?
16. How can you upgrade an installed package to its latest version using pip?
Lecture 8: Files and Streams: Saving and
Loading Data

In programming, the concepts of files and streams are central to managing data and
facilitating input/output (I/O) operations. A file is essentially a container for storing
data persistently on a storage medium such as a hard disk, SSD, or even a network drive.
Files allow programs to save information between executions; for example, a program
might store user preferences, configuration settings, or data logs in a file. Files can come
in various formats—plain text files, binary files, CSVs, JSON, XML, and more—and each
type serves a different purpose. Text files, for instance, store human-readable data, while
binary files contain data in a format that is optimized for efficient reading and writing
by machines.
Files are accessed and manipulated using various operations, such as opening, read-
ing, writing, and closing. In many programming languages, these operations are encap-
sulated in libraries or built-in functions. For example, in Python, the open() function
is used to create a file object, which can then be used to read or write data. The mode
in which a file is opened—such as read ("r"), write ("w"), or append ("a")—determines
how the file will be accessed. Using a context manager (the with statement in Python) is
a best practice, as it ensures that files are properly closed after the necessary operations
are completed, thus preventing resource leaks and data corruption.
On the other hand, streams refer to the concept of continuous data flow. Whereas
files represent static data stored on disk, streams are abstractions for handling data that
is in transit. Streams can be seen in two major categories: input streams and output
streams. An input stream allows a program to receive data sequentially, such as reading
from the keyboard (standard input) or receiving data from a network socket. Conversely,
an output stream sends data from a program to a destination, such as the console
(standard output), a file, or a network destination.
One of the critical characteristics of streams is that they handle data sequentially.
This means that when you read from an input stream, you typically process the data in
the order it arrives. This behavior is particularly useful when dealing with large datasets
or real-time data, where it might not be feasible or efficient to load all the data into
memory at once. For instance, when processing a massive log file, reading it line by line
as a stream is often more practical than loading the entire file at once.
Standard streams—stdin, stdout, and stderr—are provided by the operating system
to facilitate communication between a program and its environment. Standard input
(stdin) allows programs to accept user input or piped data from other processes. Standard
output (stdout) is used to display the results of a program, and standard error (stderr) is
dedicated to error messages and diagnostics. By using these streams, programs can be
more flexible and interactive. For example, a command-line tool might read a file name
from stdin and output the processed results to stdout, while any errors encountered
during processing are sent to stderr.
The interplay between files and streams is common in many programming scenarios.
96 L E C T URE 8: FILES AND STREAMS: SAVING AND LOADING DATA

A program might open a file to read configuration settings at startup (a file operation),
and then continuously process data received over a network connection (a stream oper-
ation). This integration allows software to persist important data while also handling
dynamic, real-time input and output.
Managing files and streams efficiently also requires careful error handling and re-
source management. Operations involving files and streams can fail due to various
reasons, such as missing files, permission errors, or network disruptions. Robust pro-
grams use error handling mechanisms (like try-catch blocks or context managers) to
gracefully manage these errors and ensure that resources, such as file handles or network
sockets, are released properly.

Understanding Files in Python


A file is a container for storing data. In Python, files are objects that you can interact
with through the built-in open() function. Files can be classified into two major types:

• Text Files: These files store data as plain text (for example, .txt, .csv, .py files). The
data is encoded using a character encoding such as UTF-8.
• Binary Files: These files store data in binary format (for example, images, exe-
cutables, audio files). Binary files require special handling because they contain
non-text data.

File Paths and Directories


Files are organized in a file system using directories (or folders). When working with files
in Python, you’ll need to specify the file path—either as an absolute path or a relative
path. Python’s os and pathlib modules provide functionality to manipulate paths and
directories, making it easier to work with files in different environments.
Example using pathlib:
from p a t h l i b import Path

# C r e a t e a Path o b j e c t f o r t h e c u r r e n t d i r e c t o r y
c u r r e n t _ d i r = Path ( ’ . ’ )
d a t a _ f i l e = c u r r e n t _ d i r / " data . t x t "
Understanding how to reference files correctly is crucial when building cross-platform
applications.

Basic File Handling Operations


The cornerstone of file handling in Python is the open() function. This function returns
a file object that you can use to read from or write to a file.
Syntax:
f i l e _ o b j e c t = open ( " f i l e n a m e " , "mode" )
The mode parameter specifies the type of access you require:

• "r": Read mode (default). Opens a file for reading.


• "w": Write mode. Creates a new file or truncates an existing file.

• "a": Append mode. Opens a file for writing, appending new data to the end.

• "b": Binary mode. Added to other modes (e.g., "rb" or "wb") for binary files.

• "x": Exclusive creation. Creates a new file and fails if the file already exists.

There are multiple ways to read a file in Python:


w i t h open ( " d a t a . t x t " , " r " ) a s f i l e :
content = f i l e . read ( )
print ( content )

readline() Method: Reads one line at a time.


w i t h open ( " d a t a . t x t " , " r " ) a s f i l e :
line = f i l e . readline ()
while l i n e :
print ( l i n e . s t r i p ( ) )
line = f i l e . readline ()

readlines() Method: Reads all lines into a list.


w i t h open ( " d a t a . t x t " , " r " ) a s f i l e :
lines = fi le . readlines ()
f o r l i n e in l i n e s :
print ( l i n e . s t r i p ( ) )

Using the with statement is highly recommended because it ensures the file is auto-
matically closed after its suite finishes executing, even if an error occurs.
To write to a file, open it in write mode ("w") or append mode ("a"):
w i t h open ( " o u t p u t . t x t " , "w" ) as f i l e :
f i l e . w r i t e ( " H e l l o , World ! \ n" )
f i l e . w r i t e ( " T h i s i s a new f i l e . \ n" )

Appending to a File:
w i t h open ( " o u t p u t . t x t " , " a " ) as f i l e :
f i l e . w r i t e ( " Appending a new l i n e . \ n" )

When you open a file in write mode, it overwrites the existing file; appending mode
will keep the existing content and add new content at the end.

Working with Binary Files


Binary files are handled differently than text files. When opening a binary file, you add
the "b" flag to the mode.
For example, reading an image file:
w i t h open ( " image . j p g " , " rb " ) as f i l e :
image_data = f i l e . r e a d ( )
# The image_data v a r i a b l e now h o l d s b i n a r y data .

Writing binary data works similarly:


w i t h open ( " copy_image . j p g " , "wb" ) a s f i l e :
f i l e . w r i t e ( image_data )
98 L E C T URE 8: FILES AND STREAMS: SAVING AND LOADING DATA

Handling binary data requires understanding of encoding and decoding when work-
ing with text-based data, and it is particularly useful for tasks such as file copying, image
processing, or network communications.

Streams in Python
Streams are continuous flows of data. In Python, file objects are a type of stream. Addi-
tionally, the standard input (stdin), output (stdout), and error (stderr) are considered
streams.

• Standard Input (sys.stdin): Typically used to read user input.


• Standard Output (sys.stdout): Used to display output.
• Standard Error (sys.stderr): Used to display error messages.

Python’s sys module provides access to these standard streams:


import s y s

# Writing to stdout
s y s . s t d o u t . w r i t e ( " T h i s goes t o s t a n d a r d o u t p u t . \ n" )

# Writing to s t d e r r
s y s . s t d e r r . w r i t e ( " T h i s i s an e r r o r message . \ n" )

# Reading from s t d i n ( t y p i c a l l y used when p i p i n g i n p u t )


i n p u t _ d a t a = s y s . s t d i n . re a d ( )
These streams can be redirected. For example, you can redirect stdout to a file so
that the output of your program is written to that file instead of the console.
Streams are often buffered. Buffering is a process where data is temporarily held
in memory before being written to disk or transmitted over a network. This improves
performance by reducing the number of I/O operations. Python’s file objects typically
use buffered I/O by default, but you can control buffering behavior through parameters
in the open() function.

Advanced File and Stream Operations


Context managers are an elegant way to handle resources like files and streams. The
with statement ensures that resources are automatically released when the block of code
is exited.
Example:
w i t h open ( " d a t a . t x t " , " r " ) a s f i l e :
data = f i l e . read ( )
# F i l e i s automatically closed here .
This pattern is critical for avoiding resource leaks and ensuring that files are properly
closed even if errors occur.
File objects maintain an internal pointer that indicates the current position in the
file. You can control this pointer with the seek() and tell() methods.
tell(): Returns the current file position.
w i t h open ( " d a t a . t x t " , " r " ) a s f i l e :
print ( " Current p o s i t i o n : " , f i l e . t e l l ( ) )
f i l e . read ( 1 0 )
p r i n t ( "New p o s i t i o n : " , f i l e . t e l l ( ) )

seek(offset, whence): Changes the file position.


w i t h open ( " d a t a . t x t " , " r " ) a s f i l e :
f i l e . s e e k ( 0 ) # Go t o t h e b e g i n n i n g o f t h e f i l e .
f i r s t _ l i n e = f i l e . readline ()
print ( f i r s t _ l i n e )

Using these methods, you can read from or write to specific parts of a file, which is
useful in many advanced applications.
Text files are encoded in various character encodings, such as UTF-8 or ASCII. When
opening a file, you can specify the encoding to ensure that the text is read correctly:
w i t h open ( " d a t a . t x t " , " r " , encoding = " u t f −8" ) a s f i l e :
content = f i l e . read ( )

Specifying the correct encoding is crucial for correctly processing text that may
include non-ASCII characters.

Real-World Examples and Use Cases


Log File Processing
Log files are typically plain text files that record events and transactions. Python’s file
handling functions can be used to parse log files, extract relevant information, and
perform analysis.
Example:
w i t h open ( " a p p l i c a t i o n . l o g " , " r " ) a s l o g _ f i l e :
f o r l i n e in l o g _ f i l e :
i f "ERROR" in l i n e :
p r i n t ( " E r r o r found : " , l i n e . s t r i p ( ) )

This simple script reads a log file line by line and prints any line that contains the
word "ERROR".

Data Analysis with CSV Files


CSV files are ubiquitous in data analysis. Python’s built-in csv module or the powerful
Pandas library can be used to read, process, and analyze CSV files.
Using the csv module:
import c s v

w i t h open ( " d a t a . c s v " , " r " , n e w l i n e = ’ ’ ) a s c s v f i l e :


reader = csv . reader ( c s v f i l e )
f o r row in r e a d e r :
p r i n t ( row )

Using Pandas:
100 L E C T URE 8: FILES AND STREAMS: SAVING AND LOADING DATA

import pandas a s pd

d f = pd . r e a d _ c s v ( " d a t a . c s v " )
p r i n t ( d f . head ( ) )

These examples illustrate how file handling is a foundational skill in data analysis
and automation.

Streaming Data in Web Applications


In web development, streams are used to handle continuous data input and output. For
example, when downloading large files or processing real-time data, managing streams
efficiently ensures that your application remains responsive and efficient. Python frame-
works like Flask and Django, along with libraries like aiohttp, support asynchronous
streaming, allowing you to handle multiple connections simultaneously.
Example of streaming a response in Flask:
from f l a s k import F l a s k , Response

app = F l a s k ( __name__ )

de f g e n e r a t e _ l a r g e _ f i l e ( ) :
f o r i in range ( 1 0 0 0 ) :
y i e l d f " L i n e { i } \ n"

@app . r o u t e ( " / download " )


de f d o w n l o a d _ f i l e ( ) :
return Response ( g e n e r a t e _ l a r g e _ f i l e ( ) , mimetype= " t e x t / p l a i n " )

i f __name__ == " __main__ " :


app . run ( debug= True )

This example demonstrates how you can stream large amounts of data to a client
without loading the entire file into memory.

Best Practices for File and Stream Handling


1. Always Use Context Managers Using the with statement to open files ensures that
resources are properly managed and released. This practice prevents issues related
to resource leaks and simplifies error handling.

2. Validate File Paths and Encodings Before processing files, especially those provided
by users, validate the file paths and encodings. This minimizes errors due to
incorrect file locations or misinterpreted character encodings.

3. Handle Exceptions Gracefully File and stream operations can fail for many reasons,
including missing files, permission issues, or hardware errors. Use try-except
blocks to handle such exceptions gracefully and provide meaningful error messages.
Example:
try :
w i t h open ( " n o n e x i s t e n t . t x t " , " r " ) a s f i l e :
content = f i l e . read ( )
except F i l e N o t F o u n d E r r o r :
p r i n t ( " The f i l e was not found . P l e a s e check t h e f i l e path . " )

4. Manage Buffering When Necessary For performance-critical applications, under-


stand how buffering works and adjust the buffering behavior if needed. This can
be especially important when dealing with large files or real-time data streams.

Summary
Files and streams in Python are fundamental concepts for managing input and output
operations. Files represent persistent storage on disk, allowing programs to save and
retrieve data across multiple runs. Python provides a built-in open() function to work
with files in various modes, such as reading ("r"), writing ("w"), appending ("a"), and
handling binary data (by adding "b" to the mode). Using context managers (with the
with statement) is a best practice when working with files, as it ensures that resources
are automatically released when operations are complete, even if errors occur.
Streams, on the other hand, are abstractions for handling continuous flows of data.
In Python, file objects themselves are considered streams because they allow sequential
reading or writing of data. Additionally, Python provides standard streams like stan-
dard input (sys.stdin), standard output (sys.stdout), and standard error (sys.stderr) for
interacting with the user or other programs. These streams facilitate reading from the
keyboard, writing output to the console, and reporting error messages in a consistent
way.
Both files and streams are essential for various programming tasks—from simple
data logging and configuration file management to complex tasks like processing large
datasets or streaming data over networks. Python’s extensive support, including the io
module for more advanced stream handling and buffering options, makes it a powerful
language for building applications that require efficient data input and output. Overall,
mastery of files and streams in Python is crucial for creating robust, maintainable, and
high-performance software.

Practice Lab: Files and Streams in Python


Objectives
• Understand how to open, read, write, and append to text and binary files.

• Learn how to use context managers to ensure files are properly closed.

• Practice handling exceptions during file operations.

• Work with standard input, output, and error streams.

• Gain hands-on experience with buffering and file positioning methods.


102 L E C T URE 8: FILES AND STREAMS: SAVING AND LOADING DATA

Prerequisites
• Python 3 installed on your computer.

• A text editor or Integrated Development Environment (IDE) (e.g., Visual Studio


Code, PyCharm, Sublime Text).

• Basic knowledge of Python syntax and variables.

• Access to a terminal or command prompt for running Python scripts.

Part 1: Basic File Operations


Task 1.1: Creating and Writing to a File

1. Create a New Script File: Open your text editor and create a new Python file named
file_lab.py.

2. Write to a File: In file_lab.py, write code to create a file named example.txt in write
mode and write the following three lines:
L i n e 1 : Welcome t o t h e F i l e Lab !
Line 2 : This i s a p r a c t i c e f i l e .
L i n e 3 : Python makes f i l e h a n d l i n g e a s y .

Hint: Use the with open("example.txt", "w") as file: pattern.

3. Run the Script: Save your file and run it from your terminal or IDE. Verify that
example.txt is created and contains the expected content.

Task 1.2: Reading from a File

1. Reading Entire Content: Extend your script (or create a new function) to open
example.txt in read mode and print its entire content.
Example Code Snippet:
w i t h open ( " example . t x t " , " r " ) a s f i l e :
content = f i l e . read ( )
print ( " F i l e content using read ( ) : " )
print ( content )

2. Reading Line by Line: Next, modify your code to read the file line by line (using a
loop) and print each line with its line number.
Example Code Snippet:
w i t h open ( " example . t x t " , " r " ) a s f i l e :
f o r index , l i n e in enumerate ( f i l e , s t a r t = 1 ) :
print ( f " Line { index } : { l i n e . s t r i p ( ) } " )
Part 2: Appending to Files and Error Handling
Task 2.1: Appending Data

1. Append to the File: Write code that opens example.txt in append mode ("a") and
adds a new line:
L i n e 4 : T h i s l i n e i s appended t o t h e f i l e .

Verify by reading the file after appending.


Task 2.2: Error Handling in File Operations

1. Handling File Not Found: Write a try-except block to handle the case when you
attempt to open a non-existent file (e.g., nonexistent.txt).
Example Code Snippet:
try :
w i t h open ( " n o n e x i s t e n t . t x t " , " r " ) a s f i l e :
data = f i l e . read ( )
except F i l e N o t F o u n d E r r o r :
p r i n t ( " E r r o r : The f i l e ’ n o n e x i s t e n t . t x t ’ was not found . " )

2. Reflection:
Why is it important to use try-except blocks when dealing with file I/O? What
potential errors can occur during file operations?

Part 5: Reflection and Exploration


1. Reflect on File Operations: How does using the with statement improve file han-
dling in Python? What are the advantages of reading files line by line versus reading
the entire file at once?

2. Explore Further: Try working with different file encodings by opening a text file
with an explicit encoding parameter (e.g., encoding="utf-8"). Experiment with
the seek() and tell() methods to manipulate the file pointer and observe how file
positions change during reading or writing.

3. Document Your Findings: Write down any errors or challenges you encountered
during the lab. Describe how you resolved these issues and what you learned about
file and stream handling.

Practice Questions
1. Write a Python program that opens a text file named example.txt in read mode
using a context manager (the with statement). Read the entire content of the file
and print it to the console.

2. Question: Why is it beneficial to use a context manager when working with files?
104 L E C T URE 8: FILES AND STREAMS: SAVING AND LOADING DATA

3. Create a Python script that creates a new text file called output.txt and writes
three separate lines of text into it. Then, modify the script to open the same file in
append mode and add an additional line of text.

4. Question: Explain the difference between opening a file in write mode ("w") and
append mode ("a").

5. Write a Python program that opens a binary file named image.jpg in binary read
mode ("rb"), reads the first 20 bytes, and prints these bytes to the console.

6. Question: What does the mode "rb" mean, and why might it be used instead of
the regular text mode?

7. Using the sys module, write a simple Python program that reads a line of input
from the user via sys.stdin and then writes a custom message to sys.stdout.

8. Question: Describe the roles of sys.stdin, sys.stdout, and sys.stderr in a Python


program.

9. Use Python’s built-in csv module to write a script that reads a CSV file called
data.csv and prints each row to the console.

10. Question: How does this example illustrate the concept of streams in file handling?

11. Write a Python program that opens a text file, reads the first 10 characters, then
uses the tell() method to print the current file position. After that, use the seek()
method to return to the beginning of the file and read the first line again.

12. Question: What do the seek() and tell() methods do, and why might they be useful?

13. Write a small script to demonstrate what happens when you open an existing file
in write mode ("w") and write new content to it.

14. Question: What will happen to the existing contents of the file when it is opened
in write mode?

15. Create a Python program that attempts to open a file that does not exist. Use a
try-except block to catch the FileNotFoundError and print an appropriate error
message.

16. Question: Why is it important to include error handling when performing file
operations?

17. Write a Python script that redirects sys.stdout to a file named log.txt. Have the
program print several lines, then reset sys.stdout back to the console and print a
final message.

18. Write a code snippet that opens a file with a specific buffering size (using the
buffering parameter in the open() function) and explains how buffering can impact
performance in file I/O operations.
Lecture 9: Classes and Objects: Object Oriented
Programming

Introduction to Object-Oriented Programming


Object-Oriented Programming, or OOP, is a style of programming that organizes code
around "objects." In OOP, you write programs by creating objects that represent things
or ideas from the real world. Each object can have data (called attributes) and actions
(called methods). Think of an object as a self-contained unit that holds its own informa-
tion and can perform its own tasks. OOP helps to make your code easier to understand,
reuse, and maintain by grouping related properties and behaviors together.
Imagine you have a toy car. The toy car has properties such as color, size, and model,
and it can perform actions like moving forward, turning, and stopping. In OOP, you
could create an object called Car that has these properties and methods. Later, you can
create many toy cars from this one blueprint (or "class") without rewriting the whole
program again.

Basic Concepts in OOP


Before we start writing code, let’s learn some important terms:
• Class: A class is like a blueprint or a template. It defines what properties and
actions an object of that type will have. For example, a Car class might include
attributes like color and speed and methods like accelerate() or brake().
• Object (or Instance): An object is an individual item created from a class. If Car is
a class, then your red toy car or your blue toy car are objects (instances) of that
class.
• Attributes: Attributes are variables that belong to an object. They hold information
about the object. In our Car example, an attribute could be color or model.
• Methods: Methods are functions that belong to a class and can perform actions
using the attributes of the object. For a Car, methods might be start_engine() or
stop_engine().
• Inheritance: Inheritance allows you to create a new class (child class) that is based
on an existing class (parent class). The new class inherits all the attributes and
methods of the parent class and can also have additional features or override
existing ones.
• Encapsulation: Encapsulation means bundling the data (attributes) and code
(methods) together as a single unit or class. It also involves hiding the internal
details of the object from the outside world, so you can change how something
works internally without affecting other parts of your program.
106 L E C T URE 9: CL ASSES AND OBJECTS: OBJECT ORIENTED PROGRAMMING

• Polymorphism: Polymorphism means that different objects can be used in the


same way even if they are of different classes. It allows a common interface to be
used for different data types.

Why Use Object-Oriented Programming?


• Organized Code: OOP helps you structure your code in a way that is easy to read
and understand. Each class has its own job, and you can build complex programs
by combining simple, self-contained objects.

• Code Reuse: With classes and inheritance, you can reuse code across multiple
projects. Instead of writing the same code again, you can create a class once and
create many objects from it.

• Maintainability: When your code is organized into classes, it’s easier to update
and fix bugs. Changes made in one part of your code are less likely to affect other
parts.

• Real-World Modeling: OOP allows you to create programs that mimic real-world be-
havior. You can design objects that interact with each other, making your program
logic more intuitive.

• Extensibility: By using inheritance and polymorphism, you can build upon existing
code without rewriting everything from scratch. This makes your software more
flexible and adaptable to change.

Creating Classes and Objects in Python


In Python, classes are created using the class keyword. The basic structure of a class is
as follows:
c l a s s MyClass :
# C l a s s a t t r i b u t e s ( s h a r e d among a l l i n s t a n c e s )
c l a s s _ a t t r i b u t e = " I am a c l a s s a t t r i b u t e "

# The _ _ i n i t _ _ method i n i t i a l i z e s new i n s t a n c e s


def _ _ i n i t _ _ ( s e l f , i n s t a n c e _ a t t r i b u t e ) :
self . instance_attribute = instance_attribute # Instance attribute

# A method t o d e m o n s t r a t e b e h a v i o r
def d i s p l a y ( s e l f ) :
print ( " Instance a t t r i b u t e : " , s e l f . i n s t a n c e _ a t t r i b u t e )

Creating Objects
Once a class is defined, you can create objects (instances) of that class:
# C r e a t e an o b j e c t o f MyClass
o b j = MyClass ( " H e l l o , World ! " )
o b j . d i s p l a y ( ) # Output : I n s t a n c e a t t r i b u t e : H e l l o , World !
In this example:

• MyClass is a blueprint.

• obj is an instance of MyClass with its own copy of instance_attribute.

• The display method prints the value of the instance attribute.

This structure allows you to encapsulate related properties and behaviors within one
logical unit.

Understanding the __init__ Method and Instance


Attributes
The __init__ method in Python is a special method (often called a constructor) that is
automatically called when an object is created. It initializes the object’s attributes and
sets up any necessary state.
Example: The __init__ Method
c l a s s Person :
def _ _ i n i t _ _ ( s e l f , name , age ) :
s e l f . name = name # I n s t a n c e a t t r i b u t e f o r s t o r i n g t h e name
s e l f . age = age # I n s t a n c e a t t r i b u t e f o r s t o r i n g t h e age

def i n t r o d u c e ( s e l f ) :
p r i n t ( f " H e l l o , my name i s { s e l f . name } and I am { s e l f . age } y e a r s o l d . " )

# Creating a Person o b j e c t
p e r s o n 1 = Person ( " A l i c e " , 3 0 )
p e r s o n 1 . i n t r o d u c e ( ) # Output : H e l l o , my name i s A l i c e and I am 30 y e a r s o l d .

In this example:

• The __init__ method takes additional parameters (name and age) and assigns them
to instance attributes.

• Each instance of Person maintains its own values for name and age.

• The introduce method uses these attributes to display a message.

The use of self is important: it refers to the instance on which the method is called,
allowing each object to have its own distinct state.

Inheritance, Encapsulation, and Polymorphism in


Python
Inheritance allows a class (the child or subclass) to inherit attributes and methods from
another class (the parent or superclass). This is useful for code reuse and for creating a
hierarchical class structure.
108 L E C T URE 9: CL ASSES AND OBJECTS: OBJECT ORIENTED PROGRAMMING

c l a s s Animal :
def _ _ i n i t _ _ ( s e l f , s p e c i e s ) :
s e l f . species = species

def make_sound ( s e l f ) :
p r i n t ( "Some g e n e r i c sound " )

c l a s s Dog ( Animal ) :
def _ _ i n i t _ _ ( s e l f , name ) :
super ( ) . _ _ i n i t _ _ ( "Dog" ) # Call the parent c l a s s c o n s t r u c t o r
s e l f . name = name

# O v e r r i d i n g t h e make_sound method
def make_sound ( s e l f ) :
p r i n t ( " Bark ! " )

# C r e a t e an i n s t a n c e o f Dog
dog = Dog ( " Buddy " )
p r i n t ( dog . s p e c i e s ) # Output : Dog
dog . make_sound ( ) # Output : Bark !

Here:

• Animal is the parent class.

• Dog is a subclass of Animal that inherits its attributes and methods.

• The Dog class overrides the make_sound method to provide behavior specific to
dogs.

Encapsulation
Encapsulation means keeping the internal state of an object hidden from the outside.
Python doesn’t enforce strict private access modifiers like some other languages, but
you can indicate that an attribute is meant for internal use by prefixing its name with an
underscore.
c l a s s BankAccount :
def _ _ i n i t _ _ ( s e l f , b a l a n c e ) :
s e l f . _balance = balance # Conventionally " p r i v a t e " a t t r i b u t e

def d e p o s i t ( s e l f , amount ) :
s e l f . _ b a l a n c e += amount

def g e t _ b a l a n c e ( s e l f ) :
return s e l f . _ b a l a n c e

account = BankAccount ( 1 0 0 )
account . d e p o s i t ( 5 0 )
p r i n t ( account . g e t _ b a l a n c e ( ) ) # Output : 1 5 0

In this example, _balance is intended to be used only within the class. Encapsulation
allows you to control how this data is accessed and modified.
Polymorphism
Polymorphism lets you call the same method on different objects, and each object
responds in its own way. This is often achieved through method overriding.
c l a s s Shape :
def draw ( s e l f ) :
p r i n t ( " Drawing a shape " )

c l a s s C i r c l e ( Shape ) :
def draw ( s e l f ) :
p r i n t ( " Drawing a c i r c l e " )

c l a s s Square ( Shape ) :
def draw ( s e l f ) :
p r i n t ( " Drawing a s q u a r e " )

de f draw_shape ( shape : Shape ) :


shape . draw ( )

circle = Circle ()
s q u a r e = Square ( )

draw_shape ( c i r c l e ) # Output : Drawing a c i r c l e


draw_shape ( s q u a r e ) # Output : Drawing a s q u a r e

Polymorphism makes your code more flexible and extensible by allowing a single
interface (draw_shape) to work with different types of shapes.

Special (Magic/Dunder) Methods and Operator


Overloading
Python classes can implement special methods (also known as magic or dunder methods,
because they begin and end with double underscores) to define how objects behave
with built-in operations. These methods allow operator overloading and customization
of object behavior.

Common Special Methods


__str__ and __repr__:
Define how an object is represented as a string.
class Point :
def _ _ i n i t _ _ ( s e l f , x , y ) :
self . x = x
self .y = y

def _ _ s t r _ _ ( s e l f ) :
return f " P o i n t ( { s e l f . x } , { s e l f . y } ) "

def _ _ r e p r _ _ ( s e l f ) :
return f " P o i n t ( { s e l f . x } , { s e l f . y } ) "
110 L E C T URE 9: CL ASSES AND OBJECTS: OBJECT ORIENTED PROGRAMMING

p = Point (2 , 3)
p r i n t ( p ) # Output : P o i n t ( 2 , 3 )

__add__:
Allows you to define behavior for the + operator.
class Vector :
def _ _ i n i t _ _ ( s e l f , x , y ) :
self . x = x
self .y = y

def __add__ ( s e l f , o t h e r ) :
return V e c t o r ( s e l f . x + o t h e r . x , s e l f . y + o t h e r . y )

def _ _ s t r _ _ ( s e l f ) :
return f " V e c t o r ( { s e l f . x } , { s e l f . y } ) "

v1 = Vector ( 1 , 2)
v2 = V e c t o r ( 3 , 4 )
v3 = v 1 + v2
p r i n t ( v3 ) # Output : V e c t o r ( 4 , 6 )

__eq__:
Defines equality between objects.
c l a s s Person :
def _ _ i n i t _ _ ( s e l f , name , age ) :
s e l f . name = name
s e l f . age = age

def __eq__ ( s e l f , o t h e r ) :
return s e l f . name == o t h e r . name and s e l f . age == o t h e r . age

p e r s o n 1 = Person ( " A l i c e " , 3 0 )


pe rs o n2 = Person ( " A l i c e " , 3 0 )
p r i n t ( p e r s o n 1 == p er so n2 ) # Output : True

Special methods let you integrate your custom objects more naturally with Python’s
syntax and built-in functions.

Class Methods, Static Methods, and Properties


Python offers additional method types that allow you to work with classes in a more
flexible manner:

Class Methods:
Defined using the @classmethod decorator, these methods receive the class (cls) as the
first parameter instead of an instance. They are often used for factory methods.
c l a s s Person :
def _ _ i n i t _ _ ( s e l f , name , age ) :
s e l f . name = name
s e l f . age = age

@classmethod
def f r o m _ b i r t h _ y e a r ( c l s , name , b i r t h _ y e a r ) :
from d a t e t i m e import d a t e t i m e
c u r r e n t _ y e a r = d a t e t i m e . now ( ) . y e a r
age = c u r r e n t _ y e a r − b i r t h _ y e a r
return c l s ( name , age )

person = Person . f r o m _ b i r t h _ y e a r ( " Bob " , 1 9 9 0 )


p r i n t ( person . name , person . age )

Static Methods:
Defined using the @staticmethod decorator, these methods do not receive an implicit
first parameter (neither self nor cls). They behave like regular functions but belong to
the class’s namespace.
class MathUtils :
@staticmethod
def add ( a , b ) :
return a + b

p r i n t ( M a t h U t i l s . add ( 5 , 7 ) ) # Output : 1 2

Properties:
Properties allow you to customize access to instance attributes. The @property decorator
can be used to define getter methods, and additional decorators allow you to define
setters and deleters.
class Circle :
def _ _ i n i t _ _ ( s e l f , r a d i u s ) :
s e l f . _radius = radius

@property
def r a d i u s ( s e l f ) :
return s e l f . _ r a d i u s

@radius . s e t t e r
def r a d i u s ( s e l f , v a l u e ) :
i f value < 0 :
r a i s e V a l u e E r r o r ( " Radius cannot be n e g a t i v e " )
s e l f . _radius = value

def a r e a ( s e l f ) :
import math
return math . p i * s e l f . _ r a d i u s * * 2

c = Circle (5)
print ( c . radius ) # Output : 5
c . radius = 10
print ( c . area ( ) ) # Output : 3 1 4 .1 5 9 2 6 5 3 5 8 9 7 9 3 ( a p p r o x i m a t e l y )
112 L E C T URE 9: CL ASSES AND OBJECTS: OBJECT ORIENTED PROGRAMMING

Using class methods, static methods, and properties allows you to write cleaner,
more intuitive code, especially when you need to control how attributes are accessed or
when you want to create utility functions that logically belong to the class.

Best Practices and Common Pitfalls in Python OOP


As you learn OOP in Python, here are some best practices to consider:

1. Keep Classes Focused: Each class should have a single responsibility. This makes
your code easier to maintain and test.
2. Use Descriptive Names: Choose clear, descriptive names for classes, methods, and
attributes. This improves readability and helps others understand your code.
3. Avoid Overcomplicating Inheritance: Multiple inheritance and deep inheritance
trees can lead to complex code. Use inheritance judiciously, and consider compo-
sition as an alternative.
4. Encapsulate Data: Hide internal implementation details by marking attributes
with an underscore. Use properties to control access when necessary.
5. Write Unit Tests: Test your classes and methods to ensure they behave as expected.
Python’s built-in unittest framework or third-party libraries like pytest are great
tools for this.
6. Document Your Code: Use docstrings to explain the purpose and usage of classes
and methods. This documentation is invaluable for future maintenance and for
other developers.

Real-World Applications and Conclusion


Object-Oriented Programming in Python is widely used in many real-world applications.
Web frameworks such as Django and Flask are built on OOP principles, enabling devel-
opers to model complex systems with classes and objects. In data science, libraries like
Pandas and Scikit-Learn use OOP to provide easy-to-use interfaces for manipulating
data and building models. Even game development and desktop applications rely on
OOP to manage entities, behaviors, and interactions.
As you continue your journey with Python, you’ll find that OOP helps to structure
your code in a way that is logical, reusable, and easier to maintain. By understanding and
applying the core principles of OOP—classes, inheritance, polymorphism, encapsulation,
and abstraction—you can build robust applications that mirror real-world problems.
In this guide, we’ve covered the basics of defining classes and objects, explored
advanced topics like special methods and dynamic features, and discussed best practices
to avoid common pitfalls. With the flexibility of Python’s OOP implementation, you are
well-equipped to design and implement solutions that are both elegant and efficient.
Remember, practice is key. Experiment with creating your own classes, building small
projects, and gradually incorporating advanced features as you become more comfort-
able. OOP is not just a coding technique—it’s a way to think about solving problems
in an organized and modular manner. Happy coding, and enjoy your exploration of
Python’s powerful object-oriented programming capabilities!

Summary
Object-Oriented Programming (OOP) in Python is a programming style that organizes
code around objects and classes. In OOP, a class serves as a blueprint for creating objects
(or instances), which encapsulate both data (attributes) and behaviors (methods). This
paradigm allows you to model real-world concepts by grouping related properties and
functionalities together.
Key principles of OOP include:

• Encapsulation: Bundling data and methods within a class, which hides the internal
state of objects from the outside world. This means you interact with objects
through well-defined interfaces rather than manipulating internal details directly.

• Inheritance: Creating new classes (subclasses) that reuse, extend, or modify the
behavior of existing classes (superclasses). This promotes code reuse and helps
create a hierarchical organization of classes.

• Polymorphism: Allowing objects of different classes to be treated as objects of a


common superclass, often through method overriding. This enables one interface
to be used for a general class of actions, making code more flexible and easier to
extend.

• Abstraction: Hiding complex implementation details and exposing only the nec-
essary parts of an object, making it easier to manage and interact with complex
systems.

Python makes implementing OOP straightforward with simple syntax. The special
__init__ method, for instance, is used to initialize new objects, while other special meth-
ods (often called "dunder" methods) like __str__, __repr__, and __add__ allow you to
define custom behavior for built-in operations. Additionally, Python supports class
methods, static methods, and properties to further control how data is accessed and
manipulated within a class.
Overall, OOP in Python helps in creating modular, reusable, and maintainable code.
It enables you to design programs that closely mirror real-world problems by organizing
your code into logical, self-contained units. This not only simplifies the development
process but also makes it easier to update, debug, and extend your applications over
time.

Practice Lab: Object-Oriented Programming in Python


Objectives
• Understand how to create and use classes and objects.

• Learn how to implement inheritance and method overriding.


114 L E C T URE 9: CL ASSES AND OBJECTS: OBJECT ORIENTED PROGRAMMING

• Practice encapsulation by managing access to data.

• Explore special methods (also known as magic or dunder methods) for customizing
behavior.

• Apply OOP concepts to build simple, modular, and maintainable Python code.

Prerequisites
• Python 3 installed on your computer.

• A text editor or IDE (such as Visual Studio Code, PyCharm, or Sublime Text).

• Basic knowledge of Python syntax (variables, functions, and control flow).

Part 1: Creating a Basic Class and Instantiating Objects


Task 1.1: Define a Simple Class
1. Instructions:

• Create a new Python file called oop_lab.py.


• Define a class called Car with the following attributes: make, model, year
• Include an __init__ method to initialize these attributes.
• Write a method named display_info that prints out the car’s details.

2. Example Code:
# o o p _ l a b . py

c l a s s Car :
def _ _ i n i t _ _ ( s e l f , make , model , y e a r ) :
s e l f . make = make # Brand o f t h e c a r ( e . g . , T o y o t a )
s e l f . model = model # Model o f t h e c a r ( e . g . , C o r o l l a )
s e l f . year = year # Y e a r o f manufacture

def d i s p l a y _ i n f o ( s e l f ) :
p r i n t ( f " T h i s c a r i s a { s e l f . y e a r } { s e l f . make } { s e l f . model } . " )

# C r e a t e an i n s t a n c e o f Car and d i s p l a y i t s i n f o
my_car = Car ( " Toyota " , " C o r o l l a " , 2 0 2 0 )
my_car . d i s p l a y _ i n f o ( )

3. Reflection Questions:

• What is the purpose of the __init__ method?


• How does the display_info method use the attributes?
Practice Questions
1. What is a class and what is an object in Python? Explain the difference between
the two, and provide a simple example that demonstrates creating a class and
instantiating an object from it.

2. What is the purpose of the __init__ method in a Python class? Write a short class
called Person that initializes attributes for name and age in the __init__ method,
and includes a method to display the person’s details.

3. Define what attributes and methods are in the context of a Python class. Create
a class called Car with attributes like make, model, and year and methods such
as start_engine() and stop_engine(). Demonstrate creating an object of Car and
calling its methods.

4. What is inheritance in OOP? Explain how it promotes code reuse. Write an example
where you create a base class called Animal with a method make_sound(), and then
create a subclass Dog that inherits from Animal and overrides the make_sound()
method.

5. Explain the concept of encapsulation in Python. How can you make an attribute
“private” in Python? Write a class BankAccount that encapsulates a balance at-
tribute, using a naming convention to indicate it should be private, and include
methods to deposit, withdraw, and check the balance.

6. What is polymorphism and how does it work in Python? Write a small program
with a base class Shape that has a method draw(). Then, create two subclasses
(Circle and Square) that override the draw() method. Demonstrate how you can
call draw() on objects of both classes through a common interface.

7. Describe the difference between a class method and a static method. Create a
class called MathOperations that includes:
A static method to add two numbers. A class method that returns a string describ-
ing the class.
Show examples of how to call both methods.

8. What are properties in Python, and how do they help with encapsulation? Write a
class Circle that has a private attribute _radius. Use the @property decorator to
create getter and setter methods for radius, and add a method to compute the
area of the circle.
116 L E C T URE 9: CL ASSES AND OBJECTS: OBJECT ORIENTED PROGRAMMING
Lecture 10: Beyond the Basics: Please Help
Yourself

Learning Python is a journey that begins with mastering the basics and gradually ad-
vancing to more complex topics. Whether you are completely new to programming
or have some experience with other languages, improving your Python skills involves
a combination of study, practice, and community engagement. The following guide
presents actionable steps for beginners to follow. By embracing these strategies, you
can build your coding skills, overcome common challenges, and enjoy the process of
learning one of the most popular programming languages in the world.

Master the Fundamentals


Understand Python Syntax and Basics
The first step in improving your Python skills is to become familiar with the language’s
syntax and basic programming concepts. Start by learning how to write simple scripts,
understand data types (such as strings, numbers, lists, dictionaries, and tuples), and get
comfortable with control structures like loops and conditional statements.

• Interactive Learning: Use the Python interpreter (REPL) to experiment with code
snippets. Typing commands directly into the interpreter helps you see immediate
results and reinforces your understanding.

• Beginner Tutorials: Follow beginner-friendly tutorials on websites like Python.org,


W3Schools, and Codecademy. These tutorials often include exercises and mini-
projects that allow you to apply what you’ve learned.

• Online Courses: Consider enrolling in online courses from platforms such as


Coursera, Udemy, or edX. These courses typically cover Python basics and gradually
introduce more advanced topics. Many courses include hands-on coding exercises
and projects to help reinforce your skills.

Practice with Exercises and Small Projects


Regular practice is key to improving any programming skill. Work on exercises that chal-
lenge you to apply what you’ve learned in different ways. Start with simple projects like
a calculator or a text-based game, and gradually progress to more complex applications.

• Coding Challenges: Websites like HackerRank, Codewars, and LeetCode offer chal-
lenges that can help sharpen your problem-solving abilities in Python.

• Project-Based Learning: Choose projects that interest you. For example, if you
enjoy data analysis, try building a small project using CSV files and the Pandas
118 L E C T URE 10: BEYOND THE BASICS: PLEASE HELP YOURSELF

library. If you are interested in web development, experiment with Flask or Django
to create a simple web application.

• Daily Coding: Aim to write code every day. Even if it’s only a small script or a few
exercises, consistent practice helps solidify concepts and develop muscle memory
for coding patterns.

Develop Good Coding Habits


Read and Understand Others’ Code
Improving your Python skills isn’t just about writing your own code—it’s also about
learning from the code of others. Reading open-source projects and code examples can
expose you to different programming styles and best practices.

• GitHub Exploration: Browse repositories on GitHub to see how experienced devel-


opers structure their projects. Look for well-documented code and try to under-
stand how functions and classes are organized.

• Code Reviews: Participate in code reviews, even if informally, by sharing your code
with friends or online communities.

• Getting feedback on your work can highlight areas for improvement and introduce
you to new techniques.

• Documentation: Read the official Python documentation and documentation


for popular libraries. Good documentation explains the design decisions behind
certain functions and helps you understand how to use them effectively.

Follow Python Style Guides


Consistent coding style improves readability and makes it easier for others (and yourself)
to maintain code over time. Python’s style guide, PEP 8, provides recommendations on
naming conventions, code layout, and formatting.

• Tools: Use tools like flake8 or pylint to automatically check your code for style
issues. These tools can help you learn and adhere to PEP 8 guidelines.

• Refactoring: Regularly review and refactor your code. Look for ways to make your
code more modular, remove redundancy, and improve clarity. This practice not
only improves your current project but also teaches you how to write cleaner code
in the future.

Learn to Debug and Test Your Code


Every programmer encounters bugs. Learning effective debugging techniques is essential
for improving your coding skills.
• Print Statements and Logging: Start with simple debugging using print statements.
Once you’re comfortable, explore Python’s logging module for more advanced
debugging.
• Debuggers: Learn how to use a debugger in your IDE (such as the built-in debugger
in Visual Studio Code or PyCharm). Stepping through your code line by line can
help you understand the flow and locate errors.
• Unit Testing: Write tests for your code using Python’s built-in unittest framework
or third-party libraries like pytest. Testing ensures your code behaves as expected
and helps prevent future bugs when making changes.

Engage with the Python Community


Participate in Online Forums and Groups
Joining communities can accelerate your learning by allowing you to ask questions, share
experiences, and collaborate on projects.

• Stack Overflow: Use platforms like Stack Overflow to ask questions when you’re
stuck and learn from the answers provided by experienced developers.
• Reddit and Discord: Subreddits such as r/learnpython and various Python Discord
channels are great places to interact with peers and get advice.
• Local Meetups: Look for local Python user groups or meetups. Participating in local
events or hackathons can expose you to real-world applications and networking
opportunities.

Contribute to Open-Source Projects


Once you have a basic understanding of Python, contributing to open-source projects is
an excellent way to improve your skills. It allows you to work with larger codebases and
learn from seasoned developers.

• Find a Project: Start with projects that welcome beginners. Many open-source
projects tag issues as “good first issue” to help newcomers get started.
• Collaborate: Collaborating on open-source projects teaches you about version
control (using Git), project management, and code review processes. It also helps
build your coding portfolio.

Create a Personal Portfolio


Building a portfolio of projects is a great way to track your progress and showcase your
skills to potential employers or collaborators.

• GitHub: Host your projects on GitHub and include clear README files that explain
the purpose of each project, how to run it, and what you learned.
120 L E C T URE 10: BEYOND THE BASICS: PLEASE HELP YOURSELF

• Blogging: Consider writing blog posts about your learning journey. Documenting
your challenges and breakthroughs not only reinforces your knowledge but also
helps others who are learning.

Explore Advanced Topics Gradually


Deepen Your Knowledge Over Time
Once you’re comfortable with the basics, gradually explore more advanced topics. Python
is a versatile language with applications in many fields.

• Data Science: Learn libraries like NumPy, Pandas, and Matplotlib if you’re inter-
ested in data analysis.

• Web Development: Explore frameworks like Flask or Django to build web applica-
tions.

• Automation and Scripting: Write scripts to automate repetitive tasks, such as file
handling, web scraping, or data processing.

• Object-Oriented Programming (OOP): As you advance, deepen your understand-


ing of OOP by learning about design patterns, inheritance hierarchies, and best
practices for writing maintainable code.

Stay Updated and Keep Learning


Python is continuously evolving, and new libraries and tools are constantly being de-
veloped. Follow Python news, blogs, and podcasts to stay informed about updates and
trends in the community.

• Continuous Learning: Make learning a habit. Dedicate time each week to reading
articles, watching tutorials, or experimenting with new libraries.

• Courses and Certifications: Consider taking advanced courses or certifications


that focus on specialized areas of Python. This can provide a structured path for
learning and improve your career prospects.

Conclusion
Improving your Python skills is a gradual process that involves understanding the fun-
damentals, practicing regularly, and engaging with the broader community. Start with
mastering the basics, and then challenge yourself with coding exercises, small projects,
and real-world applications. Develop good coding habits by reading others’ code, fol-
lowing style guidelines, and continuously debugging and testing your programs. By
participating in online forums, contributing to open-source projects, and building a
personal portfolio, you not only accelerate your learning but also build a network that
can support your growth as a developer.
Remember that every programmer makes mistakes—each error is an opportunity to
learn and improve. With persistence, curiosity, and the right resources, you will find that
your Python skills grow stronger every day. Enjoy the journey, celebrate your progress,
and keep coding!
Happy coding, and may your Python journey be both rewarding and fun!

You might also like