Introduction to Computer Systems and Programming_Com1201
Introduction to Computer Systems and Programming_Com1201
Introduction to
Computer Systems and
Programming
Com1201
For First Level
General
Prepared by
DR. MOSTAFA HERAJY
DR. DOAA EL-MORSHEDY
2024-2025
Contents
Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
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
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.
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.
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.
2. Error Detection and Reporting: During the translation process, the compiler checks
the source code for syntactic and semantic errors.
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
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.
• 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.
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.
• 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.
• 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.
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.
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?
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?
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?
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
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
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.
This confirms that your Python environment is correctly set up and that the pro-
gram is running as expected.
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
# 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 = ’ / ’
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:
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.
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.
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.
# 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 ! "
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
• Reflection Questions
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.
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
• Python uses indentation to define the code inside the if block (usually 4 spaces or
a tab).
• 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.
• Output:
• 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.
• 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
• 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 .
• Output:
Login S u c c e s s f u l
40 L E C T URE 3: CONDITIONAL STATEMENTS: MAKING DECISIONS
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
• 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 .
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 .
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.
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:
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 .
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
• 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.
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:
• attendance >= 75 is also True, so "You also have good attendance." is printed.
• 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
• Output:
Explanation:
• Output:
Explanation:
• num
• Output:
V a l i d username .
Explanation:
• Output:
You a r e a t e e n a g e r .
Explanation:
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
• Output:
Login S u c c e s s f u l
• 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.
# 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 . " )
python i f _ s t a t e m e n t . py
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 .
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 .
# 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
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 . " )
E n t e r a number : 0
The number i s z e r o .
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.”
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.
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.).
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.).
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
• Output:
1
2
3
4
5
Explanation:
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:
• Output:
0
2
4
6
8
Explanation:
• Output:
1
2
• Output:
1
2
4
5
Explanation:
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
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.
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 )
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
1
2
3
4
5
Explanation:
• The loop stops when num > 5.
56 L E C T URE 4: LOOPS: REPEATING TASKS
• Output:
1
2
Explanation:
• Output:
1
2
4
5
Explanation:
• 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).
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.
Prerequisites
• Python installed (Download Python).
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 )
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
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
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.
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.
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 ] )
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
• Output:
50
30
10
• Output:
[ 1 0 , 20 , 100 , 40 , 50]
• Output:
[ 1 0 , 15 , 20 , 30 , 40]
Removing Elements
numbers = [ 1 0 , 2 0 , 3 0 , 4 0 , 5 0 ]
• Output:
[20 , 40 , 50]
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 ]
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 ]
• Output:
Index 0: 10
Index 1: 20
Index 2: 30
Index 3: 40
Index 4: 50
• Output:
[ 1 0 , 20 , 30 , 40 , 50]
[50 , 40 , 30 , 20 , 1 0 ]
• sort() sorts the list in place, meaning it changes the original list.
• Output:
[ 1 0 , 20 , 30 , 40 , 50]
• Output:
[50 , 40 , 30 , 20 , 1 0 ]
• 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 ]
• Output:
[ ’ a p p l e ’ , ’ banana ’ , ’ c h e r r y ’ , ’ d a t e ’ ]
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 ’ ]
• Output:
[ ’ k i w i ’ , ’ a p p l e ’ , ’ c h e r r y ’ , ’ banana ’ ]
• Output:
[ 1 2 , 23 , 34 , 45 , 67]
• Output:
[ ( ’ David ’ , 6 5 ) , ( ’ Bob ’ , 7 2 ) , ( ’ A l i c e ’ , 8 5 ) , ( ’ C h a r l i e ’ , 9 0 ) ]
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
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
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 ] )
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 )
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 " )
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.
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.
• 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 . " )
• 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
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 !
• "Alice" and "Bob" are arguments passed when calling the function.
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 } " )
• Output:
• 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.
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
• 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:
• Output:
15
• Output:
name : A l i c e
age : 25
c i t y : New York
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
• Output:
25
25
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.
• 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
Lab Instructions
• Tasks
4. Write a function fibonacci(n) that returns the nth Fibonacci number using re-
cursion.
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.
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.
# 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.
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 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
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.
• 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.
• N-Dimensional Array Object: The primary data structure in NumPy is the ndarray,
which can represent arrays of any dimensionality.
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
# 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 )
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.
• 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
# 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.
• Plotting Functions: Support for various plot types including line, scatter, bar, his-
togram, and pie charts.
• Integration: Works well with Pandas and NumPy, making it easy to visualize data
directly from arrays or DataFrames.
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
# 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.
• Simple API: Intuitive methods for GET, POST, PUT, DELETE, and other HTTP
requests.
• Session Objects: Manage and persist settings across multiple requests, such as
cookies and headers.
import r e q u e s t s
# 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
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.
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.
• 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.
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 } ! "
: 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.
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.
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.
# 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
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 . "
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
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.
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 : " ) )
2. Run the Main Script In your terminal, ensure you are in the my_package_lab
directory and run:
python main . py
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.
• 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.
# 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.
• "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.
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.
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.
# 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" )
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.
This simple script reads a log file line by line and prints any line that contains the
word "ERROR".
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.
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"
This example demonstrates how you can stream large amounts of data to a client
without loading the entire file into memory.
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 . " )
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.
• Learn how to use context managers to ensure files are properly closed.
Prerequisites
• Python 3 installed on your computer.
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 .
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.
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 .
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?
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.
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
• 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.
# 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.
This structure allows you to encapsulate related properties and behaviors within one
logical unit.
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 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.
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:
• 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 " )
circle = Circle ()
s q u a r e = Square ( )
Polymorphism makes your code more flexible and extensible by allowing a single
interface (draw_shape) to work with different types of shapes.
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
Special methods let you integrate your custom objects more naturally with Python’s
syntax and built-in functions.
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 )
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.
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.
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.
• 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.
• 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).
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:
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.
• 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.
• 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.
• 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.
• 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.
• 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.
• 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.
• 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.
• 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.
• Continuous Learning: Make learning a habit. Dedicate time each week to reading
articles, watching tutorials, or experimenting with new libraries.
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!