RST Python Book (1)
RST Python Book (1)
Python Programming
Guide
.
m
ru
Fo
ST
R
ht
ig
yr
op
C
.
m
2.4 Setting Up the Python Development Environment..................................................... 13
Chapter 3: Data Types and Variables................................................................................. 15
3.1 Introduction to Data Types......................................................................................... 15
ru
3.2 Data Types in Python................................................................................................. 15
3.3 Python's Integer Type (int)......................................................................................... 16
Fo
3.4 Python's Float Type (float)..........................................................................................17
Aside: PEMDAS - Order of Operations in Python...................................................... 18
3.5 Variables: The Concept and Python Implementation................................................. 19
ST
3.5.1 The Concept of Variables.................................................................................. 19
3.5.2 Variables and Memory.......................................................................................19
3.5.3 Variables in Python............................................................................................19
3.5.3.1 Variable Naming Conventions and Restrictions....................................... 20
R
.
m
4.1 The input() Function................................................................................................... 39
4.2 Conditional (Relational) Operators............................................................................. 40
4.3 Introduction to Branching and Conditionals................................................................41
ru
4.3.1 If/Elif/Else Statements in Python....................................................................... 41
4.3.1.1 if Statement.............................................................................................. 41
Fo
4.3.1.2 elif Statement............................................................................................42
4.3.1.3 else Statement..........................................................................................43
4.3.1.4 Chaining if, elif, and else.......................................................................... 43
ST
4.3.2 More Examples of Conditionals in Python.........................................................44
4.4 Truthy and Falsy Values............................................................................................. 45
4.5 Logical Operators....................................................................................................... 47
R
.
m
5.2.8.3 The index() Method.................................................................................. 66
5.2.8.4 The count() Method.................................................................................. 66
5.2.8.5 The sort() Method..................................................................................... 66
ru
5.2.8.6 The reverse() Method............................................................................... 67
5.2.8.7 The copy() Method (Continued)................................................................67
Fo
5.2.8.8 The clear() Method................................................................................... 67
5.2.9 The in Keyword and Lists.................................................................................. 68
5.2.9.1 Basic Usage............................................................................................. 68
ST
5.2.9.2 The not in Keyword...................................................................................68
5.2.9.3 The in Keyword with a Loop..................................................................... 68
5.2.10 List Slicing....................................................................................................... 69
R
.
m
5.4.4 Looping Over a Tuple........................................................................................ 82
5.4.5 Tuple Methods...................................................................................................82
5.4.6 Immutability of Tuples........................................................................................83
ru
5.4.7 Tuples vs Lists...................................................................................................83
5.4.8 Tuple Packing and Unpacking...........................................................................84
Fo
5.4.9 Tuple Comprehension....................................................................................... 84
5.5 Python Sets................................................................................................................ 85
5.5.1 Introduction........................................................................................................85
ST
5.5.2 Accessing Elements.......................................................................................... 85
5.5.3 Set Operations.................................................................................................. 85
5.5.3.1 Union........................................................................................................ 85
R
5.5.3.2 Intersection............................................................................................... 86
5.5.3.3 Difference................................................................................................. 86
5.5.3.4 Symmetric Difference............................................................................... 86
ht
5.5.4.2 remove()................................................................................................... 87
5.5.4.3 discard()....................................................................................................87
yr
5.5.4.4 pop()......................................................................................................... 87
5.5.4.5 clear()....................................................................................................... 88
5.5.5 Set Comprehension...........................................................................................88
op
.
m
6.8.1 The *args Argument........................................................................................ 100
6.8.2 The **kwargs Argument.................................................................................. 100
6.8.3 Using *args and **kwargs Together.................................................................100
ru
6.8.4 Parameter Ordering.........................................................................................101
6.9 Argument Unpacking and Dictionary Unpacking in Python Functions..................... 101
Fo
6.9.1 Argument Unpacking with *............................................................................. 101
6.9.2 Dictionary Unpacking with **........................................................................... 102
6.9.3 Mixed Unpacking with * and **........................................................................ 102
ST
6.10 Lambda Functions in Python..................................................................................103
6.10.1 Understanding Lambda Functions................................................................ 103
6.10.2 Why Use Lambda Functions?....................................................................... 103
R
.
m
8.2.7 Real-World Example........................................................................................134
8.3 Inheritance and Polymorphism.................................................................................136
8.3.1 Concept of Inheritance, Subclasses, and Superclasses................................. 136
ru
8.3.2 Implementing Inheritance in Python................................................................ 136
8.3.3 Method Overriding (Polymorphism in OOP)....................................................137
Fo
8.3.4 The super() Function....................................................................................... 137
8.3.5 Multiple Inheritance......................................................................................... 137
8.3.6 Real-World Example........................................................................................138
ST
8.4 Special (Dunder) Methods........................................................................................139
8.4.1 Understanding Special Methods..................................................................... 139
8.4.2 Overloading Operators in Python.................................................................... 139
R
.
Every action that a computer performs, from complex scientific calculations and rendering
m
video game graphics to browsing the web and even displaying the time, is guided by
programming. Even the simplest tasks like making coffee using a smart coffee machine
ru
involve some form of programming.
Programming languages allow us to interface with computers and utilize their processing
Fo
power. While computers are incredibly fast and accurate at doing repetitive tasks, they
require detailed instructions to perform these tasks. This need for explicit instruction is where
programming languages come in.
ST
1.2 Python's Role in the Programming World
R
Enter Python, one of the most popular programming languages in the world. Python was
created by Guido van Rossum, and it was first released in 1991. Named not after the snake,
but after the British comedy show "Monty Python's Flying Circus," Python is renowned for its
ht
design philosophy, which emphasizes code readability and syntax that allows programmers
to express concepts in fewer lines of code than might be possible in other languages.
ig
executed line by line by the Python interpreter, which is software that executes code directly
and freely available on most platforms. This feature of Python makes it easier to debug and
op
Moreover, Python is a versatile language, used in various fields like web and software
C
development, data analysis, machine learning, artificial intelligence, scientific computing, etc.
It is used by some of the world's largest organizations, including NASA, Google, and IBM, as
well as individual programmers and hobbyists.
Some of the reasons why we choose Python over other languages include:
2. Broad Standard Library: Python comes with a vast standard library that includes
areas like internet protocols, string operations, web services tools, and operating
system interfaces. Many high use programming tasks are already scripted into the
standard library which reduces the length of code to be written significantly.
3. Scalability and Speed: Python's productivity and speed are quite substantial which
makes it a popular choice in industries. Companies that prioritize productivity and
speed in project development choose Python.
.
m
4. Wide Support for Libraries and Frameworks: Python is also rich with several
libraries and frameworks that make the application development process faster and
easier. For example, libraries like NumPy and SciPy are useful for scientific
ru
computation, Pandas is for data analysis and manipulation, and frameworks like
Django and Flask assist in web development.
Fo
5. Thriving Community: Python has a large, active community of developers who are
always ready to provide help and support. This community also consistently
contributes to developing and upgrading Python libraries and frameworks, making
ST
Python ever more powerful and user-friendly.
Python, owing to its simplicity, versatility, and powerful standard library, has wide-ranging
applications across diverse domains. From automating small tasks on your computer to
ht
running large web servers, Python has the breadth and depth to cater to various use cases.
software. Python is powerful enough to create advanced applications and yet simple
enough to write quick scripts to automate repetitive tasks.
op
extensive library support makes it easy to interact with your operating system,
manipulate files and directories, and automate many other tasks. Libraries like os,
sys, shutil, and glob provide functionalities for these purposes.
4. Data Analysis and Visualization: Python is a popular tool in data analysis and data
visualization. Libraries like Pandas make it easy to manipulate large datasets, while
Matplotlib and Seaborn are excellent tools for creating static, animated, and
interactive visualizations in Python. Data scientists, statisticians, and analysts often
use these libraries to gain insights from data and present these findings in a visually
appealing and understandable way.
.
Libraries like Scikit-learn provide simple and efficient tools for predictive data
m
analysis, while libraries like TensorFlow and PyTorch provide the tools to work with
artificial neural networks for deep learning models. Additionally, libraries like Keras
ru
provide a high-level interface to other libraries, like TensorFlow, making it even easier
to create deep learning models.
Fo
6. Network Programming and Automation: Python is often used in network
programming and automation tasks. With libraries such as Scapy, network
programmers can create, manipulate, send, and receive network packets. In network
automation, Python is frequently used to automate various network configuration
ST
tasks, monitor network status, and perform network diagnostics. Network engineers
use Python to interact with APIs to integrate network devices and applications,
implement SDN (Software-Defined Networking), and more.
R
7. Game Development: While Python might not be as commonly used for game
development as languages like C# (used in Unity) or C++ (used in Unreal Engine), it
ht
still has uses in this field. Pygame is a Python library that is great for learning game
development. It's also used for prototyping games, and even for developing
full-fledged indie games.
ig
8. Cybersecurity: Python is also popular in the cybersecurity field due to its simplicity
yr
and wide range of libraries that can scan, spoof, and script cybersecurity tasks.
Libraries such as Nmap, Yara, and Requests can help with network scanning,
malware analysis, and sending HTTP requests, respectively.
op
During the late 1980s, van Rossum was part of a team at Centrum Wiskunde & Informatica
(CWI), a research institute in the Netherlands, working on a language called ABC. ABC was
In December 1989, during the Christmas holidays, van Rossum decided to start a project to
keep himself occupied. Being unsatisfied with the complexity of languages like C++ and the
limitations of scripting languages like ABC and Unix shell, he aimed to create a language
that struck a balance between simplicity and power.
.
m
● Provided users a way to create their own types
● Was suitable for daily tasks, allowing for short development times
ru
With these goals in mind, he began work on Python. The language was named after the
British comedy series "Monty Python's Flying Circus," of which van Rossum was a fan. He
Fo
wanted a name that was short, unique, and slightly mysterious, so he decided that Python fit
the bill.
Python was first released in 1991, and over the years, it has been updated and improved
ST
through various versions. Python has always emphasized simplicity and beauty, striving to
make complex tasks accessible and user-friendly. This philosophy has made Python a
popular choice for beginners and experts alike.
R
Van Rossum remained Python’s chief decision-maker and project leader for many years,
making the final say in any disputes or decisions in the Python development process.
ht
Despite stepping down from his role as the BDFL in July 2018, van Rossum's vision and
philosophy continue to guide Python's development and its community.
ig
His creation, Python, has grown to be one of the most popular and influential programming
languages in the world. Today, it is used by millions of developers and is at the forefront of
yr
Regardless of your operating system - be it Windows, Linux, or macOS, we have got you
covered. Let's break down the process for each operating system.
.
● To verify the installation, open a new Command Prompt window (search cmd in
m
Windows search and hit Enter).
● Type python --version and hit Enter. This command should return the version of
ru
Python that you just installed.
Fo
Most Linux distributions come preinstalled with Python. However, it might not be the latest
version. Here's how you can install the latest Python on Ubuntu (a popular Linux
ST
distribution).
● Update the package lists for upgrades and new package installations: sudo apt
update
ht
● Once the installation is complete, you can verify the installed version by typing
python3 --version.
op
● If you want to install Python on other Linux distributions, the steps are similar, but the
commands might vary slightly according to the package manager the distribution
uses.
C
.
Python that you just installed.
m
With Python installed on your system, you're now ready to start writing Python programs!
ru
2.4 Setting Up the Python Development Environment
Fo
While Python is now installed on your system, you might find the basic command-line
interface a bit hard to work with. For a more productive setup, you may consider installing a
code editor or an Integrated Development Environment (IDE).
ST
Some popular choices for Python development include:
● Visual Studio Code (VS Code): A lightweight but powerful source code editor
R
available for Windows, Linux, and macOS. It comes with built-in support for Python,
and other languages can be added via extensions.
ht
● Sublime Text: A sophisticated text editor for code, markup, and prose. It's
lightweight, powerful, and highly extendable. With a Python plugin, Sublime Text can
be a great Python development tool.
The choice of code editor or IDE generally depends on your specific needs and preferences,
so it's good to experiment and find the one that suits you best.
With Python installed and a development environment set up, you're now ready to start your
journey with Python programming!
In the next chapter, we'll cover Python basics, starting with Python syntax, variables, data
types, and then move on to more complex topics such as control flow and functions. Stay
tuned!
.
m
ru
Fo
ST
R
ht
ig
yr
op
C
For instance, if we're dealing with whole numbers like 1, 2, or 500, we have a specific data
.
m
type for that. Similarly, if we need to work with decimal numbers or true and false values,
there are different data types for these as well.
ru
While it's important to note that different programming languages may have different data
types and ways of handling them, the core concept remains similar across languages. This
Fo
understanding will be crucial as we dive deeper into programming, because it allows us to
predict how our data will behave and interact, and to write code that's more efficient and less
prone to errors.
ST
At this point, you might be wondering, "how do we use these data types in our code?" This is
where an important concept comes in that we'll delve into shortly: the concept of 'variables'.
But before we dive into that, we first took a detailed look at two very important data types in
R
Python: numbers (int and float). These data types, which represent whole numbers and
decimal numbers respectively, form the backbone of numerical operations in Python. Once
we've grasped these, we'll be ready to explore variables, and how they tie into the concept of
ht
data types.
Here are some of the basic types found in many programming languages:
ig
Understanding these data types is important as they form the basis of data manipulation,
data structure design, and complex problem solving.
.
m
Let's delve into the details of int and float.
ru
3.3 Python's Integer Type (int)
In Python, the int type is used to represent integer values - positive or negative whole
Fo
numbers without a fractional component.
Python supports a variety of operations on integers, including addition (+), subtraction (-),
ht
multiplication (*), division (/), floor division (//), modulus (%), and exponentiation (**). Here
are examples of these operations:
ig
# addition
yr
print(10 + 2) # Output: 12
op
# subtraction
print(10 - 2) # Output: 8
C
# multiplication
print(10 * 2) # Output: 20
# division
print(10 / 2) # Output: 5.0
# floor division
print(10 // 2) # Output: 5
# modulus
# exponentiation
print(10 ** 2) # Output: 100
.
Here's how we can use a floating-point number in Python:
m
ru
3.14
Operations similar to integers like addition (+), subtraction (-), multiplication (*), division (/),
Fo
floor division (//), modulus (%), and exponentiation (**) can also be performed on floats.
# addition
ST
print(10.5 + 2.3) # Output: 12.8
# subtraction
R
# multiplication
ht
# division
print(10.5 / 2.3) # Output: 4.565217391304348
yr
# floor division
print(10.5 // 2.3) # Output: 4.0
op
# modulus
print(10.5 % 2.3) # Output: 0.1999999999999993
C
# exponentiation
print(10.5 ** 2.3) # Output: 199.5262314968879
While the int and float types in Python are used to represent numbers, there's more to
Python data types than these. But before we explore those, it will be beneficial to understand
how we can store these int or float values for repeated use in our programs. That's where
the concept of 'variables' will come into play, which we will discuss in the upcoming sections.
Parentheses (): Expressions enclosed in parentheses are evaluated first. This is useful
when you want to change the normal order of operations.
.
Exponents **: Next, exponents are evaluated. Python uses the ** operator for
m
exponentiation.
ru
Multiplication * and Division /: After exponents, multiplication and division are performed.
If there are multiple multiplication and division operations in a row, they are evaluated from
left to right.
Fo
Addition + and Subtraction -: Lastly, addition and subtraction operations are carried out.
Again, if there are multiple operations in a row, they are performed from left to right.
ST
Let's look at some examples to illustrate PEMDAS:
R
# Without parentheses
result = 3 + 2 * 2
print(result) # Output: 7, not 10
ht
# With parentheses
ig
result = (3 + 2) * 2
print(result) # Output: 10, not 7
yr
# Exponents
result = 2 ** 3 * 2
op
result = 20 / 2 * 5
print(result) # Output: 50, not 2
One way to conceptualize variables is to think of them like the cells in a spreadsheet. Each
cell doesn't hold the information you put into it, but rather a reference to where that
information is stored. So if you write a formula in one cell to manipulate the contents of other
.
m
cells, what you're actually doing is telling the spreadsheet how to use those references to
find the actual data, do something with it, and then store the result in a new place.
ru
In programming languages, we have the concept of variable "assignment". This is the
process of storing a value in a variable. For instance, we can assign the number 10 to a
Fo
variable called my_number, or the text "hello world" to a variable called greeting.
When your program runs, it's loaded into a part of your computer's memory called RAM
R
(Random Access Memory). This is the workspace your computer uses to execute your
program, store data, perform calculations, and so forth. Each location in RAM can be
ht
identified by an address, much like how houses on a street have unique addresses.
When you create a variable in your program, the computer allocates a piece of its memory to
ig
hold the variable's value. The variable's name is then associated with this memory location.
When your program uses this variable, the computer knows to look in the associated
yr
However, as a programmer, you generally don't need to worry about exactly where in
memory your variables are stored. This is managed by the computer and the programming
language you're using. What's important to understand is that when you assign a value to a
variable, that value is stored somewhere in memory, and you can use the variable's name to
C
access it.
Here's an example:
In this line of code, Python stores the integer 10 in a memory location and associates that
location with the name score. From this point forward, whenever score is used in the
program, Python will substitute the value that's stored in the associated memory location.
.
Rules:
m
1. Variable names must start with a letter or an underscore character.
2. A variable name can only contain alphanumeric characters and underscores (A-z,
0-9, and _ ).
ru
3. Variable names are case-sensitive (age, Age and AGE are three different variables).
Fo
Conventions:
my_variable = 10
variable1 = 20
_variable = 30
C
PI = 3.14
In Python, how you name your variables is crucial. A good variable name describes the data
it contains. Following these conventions can make your code more readable and
.
m
Typing is necessary in programming languages because it enables the compiler or
interpreter (the system that reads and runs your code) to understand how to work with your
ru
data. By knowing the type of a variable, the system can predict how much memory it needs
to allocate for that variable, what operations can be performed on it, and how the results of
those operations should be interpreted.
Fo
There are two primary approaches to typing in programming languages: dynamic typing and
ST
static typing.
program is run. This means that you must declare the type of a variable when you create it,
and you can't change the type of the variable later. Examples of statically-typed languages
include C++, Java, and Rust.
ht
On the other hand, dynamically-typed languages perform type checking at runtime, while the
program is being executed. This means that you don't have to declare the type of a variable
ig
when you create it, and you can change the type of a variable as many times as you want.
Examples of dynamically-typed languages include Python, JavaScript, and Ruby.
yr
Python is a dynamically-typed language. As we mentioned earlier, this means that you can
assign a value of any type to a variable, and you can change the type of a variable's value at
any time.
C
Here's an example:
x = 10 # Here, x is an integer
print(x)
While dynamic typing adds flexibility and ease of use, it can also lead to runtime errors. For
instance, if you try to perform an operation that's not valid for a variable's current type,
Python will throw an error:
x = 10
x = x + "Hello, World!" # This will cause a TypeError
.
This code causes a TypeError because Python doesn't know how to add an integer (x) and
m
a string ("Hello, World!").
ru
3.5.4.4 Python's Type Hints
Type hints are optional and are not enforced by Python's interpreter. The Python language
Fo
still remains dynamically-typed and it doesn't restrict the type of value you can assign to a
variable, even if you've provided a type hint. However, type hints can greatly improve code
readability and can be used by various tools to catch potential type-related errors before
ST
runtime.
Let's look at an example of how to use type hints with simple data types:
R
age: int = 20
name: str = "Alice"
ht
In this example, age: int is a type hint that indicates that age should be an integer, and
ig
name: str indicates that name should be a string. As mentioned earlier, these type hints
are optional and mainly serve for documentation and linting purposes.
yr
Now, if you were to use a tool like mypy, a static type checker for Python, it could analyse
op
your code and warn you if the variable was ever assigned a value that didn't match its type
hint. For instance, if later in your code you did:
C
age: int = 20
name: str = "Alice"
mypy would notify you of a type hint inconsistency, even though Python itself wouldn't raise
an error until runtime (and only if you used age in a context where a string wasn't
acceptable).
In conclusion, while Python's dynamic typing provides flexibility, type hints can be used as a
form of documentation to help programmers understand what types of values should be
assigned to variables, and can assist static type checking tools in identifying potential errors.
.
In Python, strings can be created by enclosing a sequence of characters within either single
m
quotes (') or double quotes ("):
ru
name = "Alice"
greeting = 'Hello, World!'
Fo
Both of these are valid ways to create strings in Python. You can choose either way based
on your preference or the requirement of your code.
ST
3.6.2 Escape Sequences in Strings
R
Sometimes, we may need to include special characters within our strings. For example, let's
say we need a string that includes a quote (" or ') character. Python provides escape
sequences for such requirements. Escape sequences start with a backslash (\) and are
ht
For example, if we want to insert a double quote inside a string, we can do it as follows:
yr
Similarly, we can use \n for a newline, \t for a tab space, and \\ to include a backslash
itself.
C
print("Hello\nWorld")
# Hello
# World
# Hello World
print("Hello\\World")
.
m
# Hello\World
ru
The double backslash \\ is used to insert a single backslash in the string. It's necessary
because the backslash character is used to introduce escape sequences, and we need a
way to include an actual backslash in a string.
Fo
Using these escape sequences, you can include special characters and formatting in your
Python strings.
ST
3.6.3 String Formatting: f-strings
Python provides several ways to format strings, and f-strings (formatted string literals) are a
R
very convenient method introduced in Python 3.6. They are prefixed with 'f' and use curly
braces {} to evaluate variables or expressions inside the string.
ht
name = "Alice"
age = 25
ig
In the above example, the variables name and age are directly placed inside the string.
Python replaces {name} with the value of the variable name, and {age} with the value of
op
age.
Python provides a set of built-in methods that you can use on strings. Below are examples of
some commonly used string methods.
.
print(text.rstrip()) # Output: " hello, world"
m
3.6.4.3 find() and replace()
ru
find() is used to find the index of a substring in a string. replace() is used to replace a
specified value with another value.
Fo
text = "hello, world"
print(text.find("world")) # Output: 7
ST
print(text.replace("world", "Python")) # Output: hello, Python
split() is used to break a string into a list of substrings based on a specified delimiter. By
default, it splits at each space.
ht
The join() method is used to concatenate a list of strings into a single string. It uses the
yr
text1 = "123"
text2 = "abc"
text3 = "abc123"
print(text1.isdigit()) # Output: True
print(text2.isalpha()) # Output: True
print(text3.isalnum()) # Output: True
.
m
3.6.4.7 count()
ru
The count() method returns the number of times a specified value appears in the string.
Fo
text = "hello, world, world"
print(text.count("world")) # Output: 2
ST
3.6.4.8 index()
The index() method is similar to find(), but raises an exception if the value is not found.
R
3.6.4.9 center()
The center() method centers a string, padding it with specified characters.
yr
text = "hello"
op
3.6.4.10 zfill()
The zfill() method adds zeros at the beginning of the string, until it reaches the specified
length.
text = "hello"
print(text.zfill(10)) # Output: '00000hello'
3.6.4.11 swapcase()
The swapcase() method returns a string where uppercase characters are converted to
© Copyright RSTForum. Sharing of this material is illegal.
26
lowercase, and vice versa.
3.6.4.12 partition()
The partition() method searches for a specified string, and splits the string into a tuple
containing three elements.
.
m
● The specified string
● The part after the string
ru
text = "I have 30 apples"
print(text.partition("30")) # Output: ('I have ', '30', ' apples')
text = "hello"
print(text.ljust(20, "-")) # Output: 'hello---------------'
ht
The isupper() and islower() methods return True if all the cased characters in the string
are uppercase or lowercase respectively.
op
text1 = "HELLO"
text2 = "hello"
C
3.6.4.15 isspace()
The isspace() method returns True if all the characters in the string are whitespace
characters, False otherwise.
3.6.4.16 istitle()
The istitle() method returns True if the string is a titlecased string, False otherwise.
.
m
3.6.4.17 expandtabs()
ru
The expandtabs() method sets the tab size to the specified number of whitespaces.
Fo
text = "H\tello, W\torld"
print(text.expandtabs(4)) # Output: 'H ello, W orld'
ST
This is not an exhaustive list. Python provides many other methods to manipulate and work
with strings. However, these are some of the most commonly used ones and a good starting
R
Remember, strings are an essential part of any programming language and Python provides
ht
a rich set of tools to work with them. With the understanding of strings, you can effectively
manipulate textual data in your Python applications. Practice using these string methods and
you will soon find them second nature.
ig
yr
This data type is named after George Boole, who first defined an algebraic system of logic in
the mid 19th century.
C
Boolean is the simplest data type with only two possible values: True and False. These are
not just words in Python, but they represent the two states of a Boolean value. In fact, the
Python interpreter recognizes them as special keywords. The primary usage of bool data
types is to represent truth values in logical expressions.
is_student = True
is_teacher = False
In Python, booleans are also a subtype of integers. Here's a unique aspect: when you
convert booleans to integers or use them in arithmetic operations, True is treated as 1, and
False is treated as 0.
print(int(True)) # Output: 1
print(int(False)) # Output: 0
.
print(True + True) # Output: 2
m
print(True + False) # Output: 1
print(False - True) # Output: -1
ru
Python also has a built-in function bool() that can convert values of other types to a
Fo
Boolean value. By default, certain values are considered "falsy"—they are interpreted as
False in a boolean context, such as None, 0, an empty string "", and empty containers like
[], {}, set() (more on these in the coming sections). All other values are considered
"truthy" and would be converted to True.
ST
print(bool(5)) # Output: True
print(bool(0)) # Output: False
R
Remember that while bool data type might seem simple on the surface, it forms the
foundation of complex logic and decision-making in your Python programs. You'll find it plays
op
a pivotal role when you start dealing with conditional statements and loops.
In Python, None is a special data type that represents the absence of a value or a null value.
It is an object of its own datatype, the NoneType. We cannot create multiple None objects
but can assign it to variables. These variables will be equal to one another.
We use None to indicate that a variable has no value. When we print a variable with the
value None, Python outputs None.
In this example, x is a variable and its value is None. We can also use None to represent an
empty state for a variable.
student_name = None
In this case, we might be planning to get the student's name later in the program, but at this
point, we're just declaring the student_name variable with no specific value.
.
We can check if a variable's value is None using the is operator:
m
x = None
ru
print(x is None) # Output: True
Fo
Unlike other programming languages, where you might use null, nil, or undefined, in
Python, we use None. However, the idea is the same: it's a way to say "this variable exists,
but it doesn't have a value yet."
ST
It's also worth noting that if you pass None to the bool() function, it will return False, which
allows None to be used in Boolean contexts.
R
crucial when dealing with data structures and when retrieving data that might not exist.
yr
one type to another. In Python, you might want to do this for various reasons, such as to
perform certain operations on variables, to meet function argument requirements, or to make
your code more readable and efficient.
C
Python provides several built-in functions that you can use for basic data type conversion.
These functions return a new object representing the converted value.
Here are some of the most commonly used data type conversion functions:
# int() conversion
print(int(2.8)) # Output: 2
print(int("10")) # Output: 10
.
# float() conversion
m
print(float(2)) # Output: 2.0
print(float("2.8")) # Output: 2.8
ru
# str() conversion
print(str(25)) # Output: '25'
Fo
print(str(True)) # Output: 'True'
# bool() conversion
ST
print(bool(0)) # Output: False
print(bool(1)) # Output: True
print(bool(None)) # Output: False
R
# dict() conversion
op
Remember, not all conversions are possible, and some may result in data loss or errors. For
example, trying to convert a string that doesn't represent a number into an integer or a float
will result in a ValueError.
In Python, understanding how and when to convert data types is an important skill. It allows
you to work more flexibly with your data and is a key part of many Python techniques and
Note: You may notice some unfamiliar terms in the data conversion examples above such
as list, tuple, set, and dict. Please do not worry about these yet. These are more complex
data types in Python, and they are used to store collections of data. We will discuss these
in great detail in upcoming chapters. For now, it's enough to know that Python provides
functions to convert data into these types, just like it does for int, float, str, and bool. As
you move forward in your Python journey, all of these concepts will start making more
sense.
.
m
3.10 Practice code
ru
1. Creating and Printing Variables
Fo
# Create two variables, 'a' and 'b', and assign them values of 3 and 4
respectively
a = 3
ST
b = 4
difference_ab = a - b
print("The difference between a and b is:", difference_ab)
C
3. String Manipulation
.
print("The last character of my string is:", my_string[-1])
m
4. String Concatenation
ru
# Concatenate and print two strings
Fo
greeting = "Hello"
name = "Alice"
message = greeting + ", " + name + "!"
ST
print(message)
5. String Repetition
R
print(cheer)
ig
lowercase_string = my_string.lower()
print("Lowercase string:", lowercase_string)
7. String Replace
.
9. Input and Output
m
ru
# Use the 'input()' function to get a user's name and greet them
name = input("What's your name? ")
print("Hello,", name, "!")
Fo
10. Input, Conversion, and Arithmetic
ST
# Ask the user for two numbers, convert them to integers, add them, and
print the result
num1 = int(input("Enter the first number: "))
R
name = "Alice"
age = 25
yr
12. PEMDAS
C
# Now, change the order of operations using parentheses and print the
result
print("Result of the expression (3 + 4) * 2 is:", (3 + 4) * 2)
.
# Create a string
m
text = "Hello, Python!"
ru
# Print the first 5 characters of the string
print("The first 5 characters:", text[:5])
Fo
# Print the last 5 characters of the string
print("The last 5 characters:", text[-5:])
ST
# Print characters from index 3 to 8
print("Characters from index 3 to 8:", text[3:8])
# Check if the string starts with "Hello" and print the result
ht
# Check if the string ends with "Python!" and print the result
print("Does the string end with 'Python!'? ", text.endswith("Python!"))
yr
num_str = str(num)
print("Type of num after conversion:", type(num_str))
.
# Use type hints while declaring a variable
m
x: int = 10
print("Value of x is:", x)
ru
19. Python Boolean Type
Fo
# Assign boolean values to two variables and print them
x = True
y = False
ST
print("Values of x and y are:", x, y)
x = None
print("Value of x is:", x)
ig
# Use the 'split()' method to split the string into words and print the
C
result
words = sentence.split()
print("Words in the sentence:", words)
# Create two variables, 'a' and 'b', and assign them some values
a = 3
b = 4
.
m
# Swap their values without using a temporary variable and print them
a, b = b, a
ru
print("Swapped values: a =", a, ", b =", b)
# Create a string
text = "Hello, Python!"
Fo
ST
# Use the 'find()' method to find the index of the substring "Python"
and print the result
R
index = text.find("Python")
print("Index of 'Python':", index)
ht
# Create a string
num_str = "1234"
yr
is_digit = num_str.isdigit()
print("Is the string made of digits?", is_digit)
C
# Create a float
pi = 3.14159
27. Zfill
.
print("Does the sentence contain the word 'easy'? ", "easy" in sentence)
m
29. String Strip
ru
# Remove leading and trailing spaces from a string and print the result
Fo
text = " Hello, Python! "
print("String after stripping spaces:", text.strip())
ST
30. Calculating Exponentials
.
name = input()
m
print(name)
ru
When this code runs, it will wait for the user to type something and press Enter. Whatever
the user types will then be stored in the name variable and printed out.
Fo
The input() function can also take one argument: a string that is printed out as a prompt
before the function starts waiting for input:
ST
name = input("What's your name? ")
print("Hello, " + name + "!")
R
In this case, the user will see the text "What's your name? " before typing their input. The
response will then be stored in the name variable. The final line concatenates the strings and
prints out a personalized greeting for the user.
ht
Now, it's important to remember that input() always returns a string. Even if the user
ig
enters a number, it will be returned as a string. If you want to use the input as a number,
you'll need to convert it using int() or float():
yr
Now, let's put all this knowledge together to build a simple currency converter program:
C
# We'll use a conversion rate of 0.85 USD to 1 EUR for this example
conversion_rate = 0.85
This simple program first prints a welcome message. Then it asks the user to input an
amount in USD, converts the string input to a float, and calculates the equivalent amount in
EUR. The result is then printed out.
.
forward and learn about conditionals and loops, you'll see how we can use input() to
m
create more complex and interesting programs.
ru
4.2 Conditional (Relational) Operators
Fo
Conditional operators, also known as relational operators, form the backbone of
decision-making in Python. These operators are used to compare values, and they return
either True or False depending on whether the condition they are testing is fulfilled.
ST
Python has the following conditional operators:
1. Equal to (==): This operator checks if the values of two operands are equal. If yes,
R
print(5 == 5) # True
ht
print(5 == 4) # False
ig
2. Not equal to (!=): This operator checks if the values of two operands are not equal.
If the values are not equal, the condition becomes true.
yr
print(5 != 5) # False
op
print(5 != 4) # True
3. Greater than (>): This operator checks if the value of the left operand is greater than
C
the value of the right operand. If yes, the condition becomes true.
4. Less than (<): This operator checks if the value of the left operand is less than the
value of the right operand. If yes, the condition becomes true.
5. Greater than or equal to (>=): This operator checks if the value of the left operand is
greater than or equal to the value of the right operand. If yes, the condition becomes
true.
.
print(4 >= 5) # False
m
6. Less than or equal to (<=): This operator checks if the value of the left operand is
ru
less than or equal to the value of the right operand. If yes, the condition becomes
true.
Fo
print(5 <= 4) # False
print(5 <= 5) # True
print(4 <= 5) # True
ST
Remember, these operators form the core of decision-making and flow control in Python, so
it's important to understand how they work. In the next section, we will use these operators
R
In the real world, we make decisions based on certain conditions: "If it is raining, I will take
an umbrella. Otherwise, I won't." Similarly, in programming, we often need to perform
yr
different actions based on different conditions. This is where the concept of 'branching'
comes into play.
op
4.3.1.1 if Statement
The if statement is the most straightforward way to control the flow of a program. It checks
if condition:
# code to execute if the condition is True
.
x = 10
m
if x > 5:
print("x is greater than 5")
ru
In this case, the condition is x > 5, which evaluates to True as 10 is indeed greater than 5.
Therefore, the statement "x is greater than 5" gets printed.
Fo
The elif statement allows you to check multiple expressions for True and execute a block
ST
of code as soon as one of the conditions evaluates to True.
Similar to else, the elif statement is optional. However, unlike else, for which there can be
R
at most one statement, there can be an arbitrary number of elif statements following an if.
if condition1:
ig
x = 20
C
if x > 30:
print("x is greater than 30")
elif x > 10:
print("x is greater than 10 but not greater than 30")
In this case, the first condition x > 30 is False, so Python skips the first print statement and
checks the next condition x > 10, which is True, so the statement "x is greater than
10 but not greater than 30" gets printed.
.
Let's see an example:
m
x = 5
ru
if x > 10:
print("x is greater than 10")
else:
Fo
print("x is not greater than 10")
In this example, the condition x > 10 is False as 5 is not greater than 10. Therefore, the
ST
else block is executed, and the statement "x is not greater than 10" gets printed.
Keep in mind, an else statement always comes after any if and elif statements, and gets
R
We can chain if, elif, and else statements to create more complex decision-making
structures. Here is an example:
ig
x = 15
yr
if x > 20:
print("x is greater than 20")
op
In this case, the first condition x > 20 is False, so Python checks the next condition x >
10, which is True, so the statement "x is greater than 10 but not greater than
20" gets printed. The else block is not executed as one of the preceding conditions is
True.
This should provide a solid understanding of how to use branching and conditionals in
Python. Keep in mind that understanding the logic and flow of conditionals is key to
developing complex programs. Practice with a variety of scenarios to become more
age = 25
.
m
if age < 13:
print("Child")
elif age < 20:
ru
print("Teenager")
elif age < 60:
Fo
print("Adult")
else:
print("Senior")
ST
In this example, an individual's age group is determined based on their age. Depending on
the age input, the program will print whether the individual is a "Child", "Teenager", "Adult",
or "Senior".
R
temperature = 30
ig
if temperature < 0:
print("Extreme Cold Alert!")
yr
print("Temperature is normal.")
This example simulates a simple temperature alert system. If the temperature falls below 0
degrees, it alerts "Extreme Cold Alert!". If it's between 0 and 20, it alerts "Cold Alert!". If the
temperature rises above 40 degrees, it alerts "Extreme Heat Alert!". Otherwise, it simply
prints that the temperature is normal.
if movie_rating >= 8:
print("Great movie!")
elif movie_rating >= 5:
print("Average movie.")
else:
print("Below average movie.")
In this example, a movie is rated based on its score. If the movie score is 8 or more, it's
considered a "Great movie!". If it's between 5 and 8, it's an "Average movie.". Otherwise, it's
.
a "Below average movie.".
m
4. Exam Grade System
ru
exam_score = 85
Fo
if exam_score >= 90:
print("Grade: A")
ST
elif exam_score >= 80:
print("Grade: B")
elif exam_score >= 70:
print("Grade: C")
R
print("Grade: F")
ig
In this example, an exam grade is determined based on an exam score. If the score is 90 or
above, the grade is 'A'. For scores between 80 and 90, the grade is 'B'. For scores between
yr
70 and 80, the grade is 'C'. For scores between 60 and 70, the grade is 'D'. For any score
below 60, the grade is 'F'.
op
Remember, these examples still follow the basic structure of if, elif, and else statements. The
conditions have simply become more complex. Practice writing your own examples and think
about how you can use branching and conditionals to make your code more dynamic and
C
flexible.
By default, an object is considered True unless its class defines a boolean value to be
.
m
# False because the string is empty
ru
if '':
print("The string is not empty.")
else:
Fo
print("The string is empty.") # This will be printed
if 0:
print("The number is not zero.")
else:
ig
In these examples, the if statement is evaluating the "truthiness" or "falsiness" of the values.
When used with if statements, Python automatically checks whether a value is True or
False. If it's True (i.e., truthy), the if block is executed. If it's False (i.e., falsy), the else
block (if present) is executed.
Understanding this concept is key when working with conditionals in Python. In the following
sections, we will see how this is crucial for creating effective, efficient, and flexible
conditional logic in our Python programs.
.
The and operator returns True if both conditions on its left and right are True.
m
print(True and True) # Returns: True
ru
print(True and False) # Returns: False
print(False and True) # Returns: False
Fo
print(False and False) # Returns: False
ST
4.5.2 or Operator
The or operator returns True if at least one of the conditions on its left or right is True.
R
The not operator reverses the truthiness of the condition that follows it.
op
These logical operators can be combined with the relational operators to create complex
conditions. Let's see an example:
age = 25
country = 'India'
In this code, we are checking if the person is at least 18 years old and if they are in India.
Only if both conditions are True will they be allowed to vote.
Complex Example
Now, let's create a more complex example:
age = 25
.
country = 'India'
m
has_voter_id = False
ru
if not has_voter_id:
print("Sorry, you must have a valid voter ID to vote in India.")
Fo
else:
print("You are eligible to vote in India.")
else:
ST
print("You are not eligible to vote in India.")
are True will they be allowed to vote. The not operator is used to reverse the
has_voter_id boolean, meaning the if condition will pass if has_voter_id is False.
ht
In this section, we'll put all that we've learned together to create a simple rock, paper,
scissors game. Here's how the game is played: rock beats scissors, scissors beats paper,
yr
if player1 == player2:
print("It's a draw!")
elif player1 == "rock":
.
print("Player 1 wins!")
m
else:
print("Player 2 wins!")
ru
else:
print("Invalid input! You have not entered rock/paper/scissors, try
again.")
Fo
In the above code, we're using the input() function to get the choices of the two players.
We're then using conditionals and nested conditionals to determine the winner based on the
ST
rules of the game.
First, we check if both players have made the same choice. If so, the game is a draw.
R
1. If Player 1 chose rock, and Player 2 chose scissors, Player 1 wins. Otherwise
(meaning Player 2 must have chosen paper), Player 2 wins.
2. If Player 1 chose scissors, and Player 2 chose paper, Player 1 wins. Otherwise
ig
Lastly, if Player 1 enters something other than rock, paper, or scissors, we print a message
telling them they made an invalid choice.
C
This game encapsulates many of the concepts we've learned: user input, strings, and
conditionals.. You can expand on this game, add more features, and handle more edge
cases as you continue to learn more about Python!
This is the essence of a loop: doing repetitive tasks efficiently and cleanly. Loops are a way
.
m
for a program to do a task a specific number of times, or until a certain condition is met. This
condition is called the loop condition.
ru
Loops have three main components: initialization (where we set the starting condition), the
condition (which, as long as it's True, keeps the loop running), and the increment (where we
Fo
change the condition so that the loop will eventually stop).
# code to be executed
ig
P
y
t
h
o
n
.
● range(start, stop) takes two arguments.
m
● range(start, stop, step) takes three arguments.
ru
1. start: Starting number of the sequence. If not provided, it defaults to 0.
2. stop: Generate numbers up to, but not including, this number.
Fo
3. step: Difference between each number in the sequence. If not provided, it defaults to
1.
Here's an example:
ST
print(range(10)) # This will output: range(0, 10)
R
9]
yr
to perform an action a certain number of times. For instance, if we wanted to print numbers
from 0 to 4, we could use a for loop with range(5):
C
for i in range(5):
print(i)
0
1
2
3
1. Counting Down
.
This code counts down from 10 to 1. The range function here starts at 10, ends before 0,
m
and decrements the counter by -1 in each iteration.
ru
sum = 0
Fo
for i in range(1, 11): # Loop from 1 to 10
sum += i
print("Sum of first 10 natural numbers is:", sum)
ST
Here, we are calculating the sum of the first 10 natural numbers. sum += i is equivalent to
sum = sum + i, meaning each time the loop iterates, the current number i is added to sum.
R
This code prints every second number from 0 to 20. The third parameter in range, the 'step',
yr
word = "Python"
C
length = len(word)
for i in range(length - 1, -1, -1):
print(word[i])
This code prints the characters of the word "Python" in reverse order. It does so by iterating
over the indices of the string in reverse order, from the last index to the first.
5. Checking Divisibility
This example prints all numbers between 1 and 100 that are divisible by both 5 and 7. The %
operator gives the remainder of a division. If i % 5 and i % 7 are both 0, i is divisible by both
5 and 7.
6. Calculating Factorial
.
n = 5
m
factorial = 1
for i in range(1, n + 1):
factorial *= i
ru
print(f"The factorial of {n} is {factorial}")
Fo
This code calculates the factorial of a number. A factorial of a number n is the product of all
positive integers less than or equal to n.
ST
7. Table of a Number
n = 5
R
8. Printing a Pattern
yr
print("*", end="")
print()
C
This prints a pattern of asterisks. The end="" argument in the print function prevents it from
printing a new line at the end of each print statement.
number = 12345
count = 0
for i in str(number):
count += 1
This code counts the number of digits in a number by converting the number into a string
and then iterating over each character (digit) in that string.
base = 2
exponent = 5
result = 1
.
m
for _ in range(exponent):
result *= base
ru
print(f"{base} to the power of {exponent} is {result}")
Fo
This code calculates the power of a number by multiplying the base with itself for the number
of times specified by the exponent. Here _ is a convention used for a variable that we don't
care about. In this case, we don't use the variable in the loop body.
ST
Remember, these are just a few examples of how for loops can be used in Python. The
possibilities are virtually endless, depending on the problem you're trying to solve. Keep
practicing and exploring other examples to solidify your understanding of loops.
R
The FizzBuzz problem: Write a program that prints the numbers from 1 to 100. But for
multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz".
ig
For numbers which are multiples of both three and five print "FizzBuzz". The rest of the
numbers should just be printed as they are.
yr
The FizzBuzz problem is a very common programming challenge often used in coding
interviews. It's a relatively simple problem, but it requires understanding of loops and
op
conditionals. Here's how you can solve it using a for loop in Python:
if i % 3 == 0 and i % 5 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
We loop over the numbers 1 through 100 using the range() function. The range function
generates a sequence of numbers, starting from the first parameter (inclusive) and ending at
the second parameter (exclusive).
.
conditions are True. So, this condition checks if i is a multiple of both 3 and 5. If it is,
m
the program prints "FizzBuzz".
● elif i % 3 == 0: This condition checks if i is a multiple of 3. If it is, the program
prints "Fizz".
ru
● elif i % 5 == 0: This condition checks if i is a multiple of 5. If it is, the program
prints "Buzz".
Fo
● else: If none of the above conditions are True (that is, if i is not a multiple of 3 or
5), the program just prints the number i.
ST
The key point here is the order of the conditions. The first condition to evaluate to True will
be the one that gets executed. This is why we check for the "FizzBuzz" case first (as it's the
most specific case), and then check for "Fizz" and "Buzz".
R
The while loop in Python is used to repeatedly execute a block of statements as long as a
certain condition is true. The basic syntax of a while loop in Python is:
ig
while condition:
# statements to execute
yr
Here, condition is a boolean expression that the while loop checks before each iteration. If
op
the condition is True, the loop will execute the indented block of code. After executing the
block of code, it goes back to check the condition again. This loop continues until the
condition becomes False. When that happens, the loop terminates, and the program
C
continues with the rest of the code after the while loop.
Key Points
● Loop Control Variable: Typically, the condition involves one or more variables that
change their values in the course of execution and control the number of times the
loop executes. These are known as the loop control variables.
i = 1
while i <= 5:
print(i)
.
i += 1
m
In this example, the loop control variable i starts at 1. The condition is i <= 5, which is
ru
True at the start, so the loop begins. Inside the loop, we first print the current value of i, then
increment i by 1 (i += 1 is equivalent to i = i + 1). When i becomes 6, the condition i <=
Fo
5 becomes False, and the loop terminates.
i -= 1
In this example, we start from 10 and decrement i by 1 in each iteration until i is no longer
ht
greater than 0.
user_input = ""
while user_input != 'q':
op
In this example, the loop continues asking the user for input until the user enters 'q'.
C
While loops are very versatile and can be used for various purposes like monitoring system
status, validating user input, etc. In the next section, we'll see some real-world-like examples
of while loops.
5.4.1 Concept
The break statement in Python is used to exit or "break" out of a loop (either for or while)
prematurely, regardless of the loop's conditional expression.
while condition:
# statements to execute
if some_other_condition:
break # break out of the loop immediately
.
m
Similarly, in a for loop:
ru
for item in iterable:
# statements to execute
Fo
if some_other_condition:
break # break out of the loop immediately
ST
When the program execution reaches the break statement, it immediately stops the current
loop execution and continues executing the next line of code after the loop.
R
5.4.2 Examples
Example 1: Stopping a while loop.
ht
count = 0
while True: # This would be an infinite loop without the break
ig
statement
print(count)
yr
count += 1
if count >= 5:
op
In this example, we start an infinite loop with while True:. The loop will continue indefinitely
C
unless we stop it manually. We increment count by 1 during each iteration, and when count
becomes 5, we use the break statement to exit the loop.
Now let's look at a complex real-world example where we can use a while loop and the
break statement together.
.
while True: # start an infinite loop
m
print("\nWelcome to the ATM!")
print("1. Show Balance")
ru
print("2. Deposit Money")
print("3. Withdraw Money")
print("4. Quit")
Fo
choice = input("Enter your choice: ")
if choice == "1":
ST
print(f"\nYour balance is: ${balance}")
balance += amount
ht
balance -= amount
else:
yr
print("\nInsufficient balance!")
op
else:
print("\nInvalid choice! Please try again.")
In this example, we have simulated a very simplified ATM machine. The program presents
the user with a menu of choices in an infinite while loop. If the user enters '4', we break out
of the loop using the break statement. If the user enters an invalid choice, the loop simply
continues, showing the menu again. This is a basic example of how ATM machines operate
in the real world.
5.5.1 Concept
The continue statement in Python is used to skip the rest of the code inside a loop (either
for or while) for the current iteration and move directly to the next iteration.
while condition:
# statements to execute
if some_other_condition:
continue # Skip the rest of this iteration and continue with
.
the next
m
# more statements
ru
Similarly, in a for loop:
Fo
for item in iterable:
# statements to execute
if some_other_condition:
ST
continue # Skip the rest of this iteration and continue with
the next
# more statements
R
5.5.2 Examples
ig
count = 0
while count < 10:
op
count += 1
if count % 2 == 0: # if count is an even number
continue # skip the print statement and move to the next
C
iteration
print(count)
In this example, the continue statement is used to skip the printing of even numbers. The
print statement is skipped each time count is an even number.
In this example, we are looping over a range of numbers from 1 to 10. When the number is
divisible by 3, we use the continue statement to skip the printing of that number and move
directly to the next iteration. So, this program will only print numbers that are not divisible by
3.
.
m
while True: # start an infinite loop
user_input = input("Enter a number (or 'q' to quit): ")
ru
if user_input == 'q':
break # if user wants to quit, break the loop
Fo
number = int(user_input)
if number % 2 == 0: # if the number is even
continue # skip the rest and move to the next iteration
ST
print(f"{number} squared is {number**2}")
In this example, we are taking a number as input from the user in an infinite loop. If the user
enters an even number, we use the continue statement to skip the calculation and printing of
R
the square of the number, and we move directly to the next iteration. Thus, this program will
only print the squares of odd numbers.
ht
Let's take the Rock, Paper, Scissors game we developed earlier and improve it by using a
while loop. We can use the loop to keep the game running until the user decides to quit.
yr
.
# Check for a valid input
m
if player2.lower() not in ['rock', 'paper', 'scissors']:
print("Invalid input. Please enter either rock, paper, or
ru
scissors.")
continue
Fo
if player1 == player2:
print("It's a draw!")
elif player1 == "rock":
ST
if player2 == "scissors":
print("Player 1 wins!")
else:
R
print("Player 2 wins!")
elif player1 == "scissors":
if player2 == "paper":
ht
print("Player 1 wins!")
else:
print("Player 2 wins!")
ig
print("Player 1 wins!")
else:
op
print("Player 2 wins!")
Explanation:
while True:
We initiate an infinite loop with 'while True'. This loop will continue until a 'break' statement is
encountered.
In these two lines, we are taking the input from the two players at each round of the game.
They can enter their choice from 'rock', 'paper' or 'scissors'.
.
m
if player1 == 'q' or player2 == 'q':
break
ru
Here, we provide a way for the players to end the game by entering 'q'. If either of the
Fo
players enters 'q', the infinite loop will be broken and the game will end.
if player1 == player2:
ST
print("It's a draw!")
elif player1 == "rock":
#... remaining game logic code
R
This is the game logic as explained previously. If both players choose the same, it's a draw.
The following lines then check the various possible combinations of choices to decide and
ht
break
op
Finally, we give the players the option to play another round. If they enter anything other than
'yes', the game will end. We use the 'lower()' function here to ensure that the comparison is
case-insensitive.
C
If the players choose to continue, the program loops back to the beginning of the 'while' loop
and starts a new round. If they choose to stop, the 'break' statement is executed and the
loop (and the game) ends.
Why do we need data structures? In programming, the process of managing and organizing
data is a critical component to write efficient code and solve complex problems. Certain data
.
m
structures are designed to hold particular types of data, and some are highly specialized to
specific tasks. For instance, if you need to frequently access elements by index, lists or
arrays would be beneficial. If you require unique items, a set is more appropriate. Therefore,
ru
the use of appropriate data structures can enhance the functionality, performance, and
efficiency of our software applications.
Fo
5.2 Python Lists
One of the most fundamental data structures in any language is the array. Python doesn't
ST
have a native array data structure, but it has the ‘list’ which is much more general and can
be used as a multidimensional array quite easily.
R
Python lists are one of the core data structures that the language offers. A list is used to
store an ordered collection of items, which might be of different types but usually they are all
of the same type. The items are ordered and can be accessed by their position in the list,
ht
This is a list of four items, all of them strings. You can also make a list of numbers (integers,
floating point, etc.), or a mix of different data types.
You can also use negative indexing to access items from the end of the list. An index of -1
refers to the last item, -2 refers to the second last item, and so on.
.
m
5.2.3 Modifying Elements
Since lists are mutable, you can modify their contents. You can change an item by referring
ru
to its position in the list. Here's how to change the second item ('banana') to 'blueberry':
Fo
fruits = ['apple', 'banana', 'cherry', 'date']
fruits[1] = 'blueberry'
print(fruits) # Output: ['apple', 'blueberry', 'cherry', 'date']
ST
5.2.4 Adding Elements
To add an item to the end of the list, use the append() method:
R
fruits.append('elderberry')
print(fruits) # Output: ['apple', 'banana', 'cherry', 'date',
ig
'elderberry']
yr
You can also insert an item at a specific position with the insert() method, which takes
two arguments: the position (or "index") and the item.
op
.
m
print(fruits) # Output: ['apple', 'cherry', 'date']
In this case, the pop() method removed the item at position 1 (the second item), which is
ru
'banana', and then it returned this item. The print() function then printed 'banana'. The last
print() function call showed that 'banana' is no longer in the list.
Fo
If you call the pop() method without any argument, it removes and returns the last item.
ST
fruits = ['apple', 'banana', 'cherry', 'date']
popped_fruit = fruits.pop()
print(popped_fruit) # Output: 'date'
R
Python also has a del statement (not a method) that you can use to remove an item at a
specific position, or to remove a slice of items. Unlike pop(), del does not return the
ig
removed item(s).
yr
.
want to add an item at the end (like append()) or at the beginning (like prepend()), but
m
somewhere in the middle.
ru
fruits = ['apple', 'banana', 'cherry']
fruits.insert(1, 'avocado')
print(fruits) # Output: ['apple', 'avocado', 'banana', 'cherry']
Fo
In this case, 'avocado' was inserted at position 1, pushing 'banana' and 'cherry' one position
to the right.
ST
5.2.8.3 The index() Method
The index() method returns the index of the first occurrence of an item.
R
print(fruits.index('banana')) # Output: 1
ig
In this case, 'banana' occurs twice, but index() only returned the position of the first
occurrence.
yr
print(fruits.count('banana')) # Output: 2
numbers = [6, 1, 5, 2, 4, 3]
.
m
numbers = [1, 2, 3, 4, 5, 6]
numbers.reverse()
ru
print(numbers) # Output: [6, 5, 4, 3, 2, 1]
Fo
The copy() method returns a copy of the list. This can be useful when you want to keep the
original list intact while modifying the copied list.
ST
fruits = ['apple', 'banana', 'cherry']
fruits_copy = fruits.copy()
fruits_copy.append('date')
R
In this example, we appended 'date' to the copied list, but the original list remained
unchanged.
ig
After using the clear() method, the 'fruits' list is now empty.
Summary
This covers the basic operations with lists. But Python lists have many more methods and
features, which we'll explore in the following sections.
Lists in Python provide a host of powerful built-in methods to make list manipulation an
efficient task. These methods can help you perform a variety of operations such as adding,
removing, searching, sorting, reversing, copying, and clearing items. Understanding how to
© Copyright RSTForum. Sharing of this material is illegal.
67
use these methods can go a long way in making your code cleaner, more efficient, and more
readable. Experimenting with different methods and scenarios will help you become more
comfortable and proficient with Python lists.
.
m
fruits = ['apple', 'banana', 'cherry']
ru
# Check if 'apple' is in the list
if 'apple' in fruits:
Fo
print('Apple is in the list!')
In this example, Python checks to see if the string 'apple' is an element in the fruits list. If it
ST
is, then it will print 'Apple is in the list!'.
Similarly, Python also provides the not in keyword which checks if a certain value does not
exist in the list.
ht
In this example, Python checks to see if the string 'date' is not an element in the fruits list. If it
op
The in keyword is also commonly used with loops to iterate over the elements of a list.
In this example, fruit is a variable that will take on each value in the fruits list, one at a time,
Summary
The in keyword, along with its counterpart not in, are simple but versatile tools for checking
the presence or absence of values in a list. When used with loops and conditionals, these
keywords can form the basis for more complex logical structures and algorithms. Experiment
with these keywords and lists to gain more confidence in using them.
.
operation for lists and other sequence data types like strings and tuples.
m
5.2.10.1 Basic Slicing
ru
The syntax for slicing is list[start:stop], where start is the index at which the slice
starts, and stop is the index at which the slice ends. The element at the start index is
Fo
included, but the element at the stop index is not included in the slice.
numbers = [0, 1, 2, 3, 4, 5]
ST
# Slice from index 1 to 4
print(numbers[1:4]) # Output: [1, 2, 3]
R
You can omit either the start index, or the stop index, or both in the slicing syntax.
ig
numbers = [0, 1, 2, 3, 4, 5]
yr
numbers = [0, 1, 2, 3, 4, 5]
numbers = [0, 1, 2, 3, 4, 5]
.
# Slice every second element
m
print(numbers[::2]) # Output: [0, 2, 4]
ru
# Slice in reverse
print(numbers[::-1]) # Output: [5, 4, 3, 2, 1, 0]
Fo
5.2.10.5 Slicing and Modifying Lists
Slicing can be used on the left side of an assignment operation to modify multiple list
ST
elements at once.
numbers = [0, 1, 2, 3, 4, 5]
R
Summary
List slicing in Python offers a flexible and powerful way to access and manipulate list data.
It's a fundamental skill for working with sequence data types in Python and is well worth
yr
numbers = [1, 2, 3, 4, 5]
Now, let's say we want to swap the second and fourth elements. In Python, this can be done
in a single line:
The right-hand side of the equation (numbers[3], numbers[1]) forms a tuple (a kind of
immutable list) containing the values of the elements at indices 3 and 1.
The left-hand side of the equation also forms a tuple, but this time it's a tuple of variables
rather than values. Python then assigns the values from the right-hand tuple to the variables
.
in the left-hand tuple. This is known as tuple packing and unpacking, a concept we will
m
explore in detail in the next chapter.
ru
Since the assignments are all done "at the same time", you can swap the values without
needing a temporary variable to hold one of the values during the swap, which you might
have needed in other languages.
Fo
This swapping mechanism can also be used to swap the values of any two variables, not
just elements in a list.
ST
a = 5
b = 10
R
This makes Python's list swapping a handy tool to have in your Python toolkit.
ht
ig
comprehension is borrowed from set builder notation in mathematics. It's a way to define and
create lists in Python in a very natural or easy way, like a mathematician is used to do.
op
that x > 0 is written as: {x | x > 0}. The pipe symbol (|) translates to "such that".
Python’s list comprehensions provide a natural way to describe lists, sets, and other
sequences and structures. Not only they're more readable and concise, but they can also
perform better than using loops and map() function.
Let's start with a simple example of how to use a list comprehension. Suppose we want to
create a list of the squares of the numbers from 0 to 9. Here's how we can do it with a for
loop:
And here's how we can do the same thing with a list comprehension:
.
The list comprehension is shorter, easier to read, and does exactly the same thing. Here's
m
the general form of a list comprehension:
ru
[expression for item in iterable]
Fo
The expression is calculated for each item in the iterable. The results are collected into a
new list, which is the value of the list comprehension.
ST
List comprehensions can also incorporate conditionals. For example, here's a list
comprehension that creates a list of the squares of the numbers from 0 to 9, but only for the
even numbers:
R
The expression is only calculated for items where the condition is true.
op
List comprehensions can be a little tricky to understand at first, but they're incredibly useful
once you get the hang of them. They can make your code more readable and efficient,
especially when you're dealing with large lists.
C
You can use both if and else in a list comprehension. This allows us to produce more
complex lists in a very compact way. Here is the syntax for it:
Let's take an example. Suppose we have a list of numbers and we want to create a new list
where each element is a string "even" if the number is even, and "odd" if the number is odd.
numbers = [1, 2, 3, 4, 5, 6]
parity = ["even" if number % 2 == 0 else "odd" for number in numbers]
print(parity) # Output: ['odd', 'even', 'odd', 'even', 'odd', 'even']
This list comprehension does the same thing as the following for loop:
.
m
numbers = [1, 2, 3, 4, 5, 6]
ru
parity = []
for number in numbers:
if number % 2 == 0:
Fo
parity.append("even")
else:
parity.append("odd")
ST
print(parity) # Output: ['odd', 'even', 'odd', 'even', 'odd', 'even']
The list comprehension is much shorter and arguably easier to understand, once you're
familiar with the syntax.
R
Here are a few more examples of what you can do with list comprehensions:
ht
s = "Hello, world!"
vowels = [c for c in s if c in 'aeiou']
4. Getting a list of all the words in a string that have 5 letters or more:
.
m
matrix = [[i*j for i in range(5)] for j in range(5)]
print(matrix)
ru
Output:
Fo
[[0, 0, 0, 0, 0],
[0, 1, 2, 3, 4],
[0, 2, 4, 6, 8],
ST
[0, 3, 6, 9, 12],
[0, 4, 8, 12, 16]]
R
In conclusion, list comprehensions are a powerful tool that make it easy to create new lists
by processing existing lists (and other iterables). They're a big part of what makes Python
such a joy to write and read.
ht
In Python, a list can contain elements of any type, including other lists. A list within another
list is called a nested list or a multidimensional list. It's a powerful concept in Python, allowing
yr
Output
The above example is a 2-dimensional list (a list of lists) that looks a bit like a table with 3
rows and 3 columns. You could imagine this representing a game board, a grid of graphical
pixels, a spreadsheet, or any number of other 2D structures.
print(nested_list[1][2]) # Output: 6
Here, nested_list[1] accesses the second sublist (remember, list indices start from 0),
then the [2] accesses the third element of that sublist.
.
5.2.13.2 Modifying Elements
m
Just like with regular lists, you can modify elements of a nested list:
ru
nested_list[1][2] = 600
print(nested_list) # Output: [[1, 2, 3], [4, 5, 600], [7, 8, 9]]
Fo
5.2.13.3 Looping Over Nested Lists
Looping over a nested list typically involves a nested loop. Here's an example of printing all
ST
elements of a 2D list:
1 2 3
yr
4 5 600
7 8 9
op
In this example, range(3) is used twice, to create three-element sublists and to make three
of these sublists. The variable _ is a convention for when you don't care about the exact
values being iterated over.
.
5.3.1 Dictionary Creation
m
Dictionaries in Python are a collection of key-value pairs, where each key-value pair maps
the key to its associated value. The keys in a dictionary must be unique (within one
ru
dictionary) but the values may not. Keys and values can be of any type, although keys are
typically numbers or strings.
Fo
To create a dictionary, you use curly braces {} containing key-value pairs separated by
commas ,. Each key-value pair is written as key: value.
ST
person = {"name": "John", "age": 30, "country": "USA"}
print(person) # Output: {'name': 'John', 'age': 30, 'country': 'USA'}
R
In this example, name, age, and country are keys, and John, 30, and USA are their
corresponding values.
ht
You can access the value for a particular key by using square brackets [] containing the
key.
yr
If the key does not exist in the dictionary, Python raises a KeyError. To avoid this, you can
use the dictionary's get() method, which returns None if the key doesn't exist.
C
You can also specify a default value to return if the key doesn't exist:
person["age"] = 31
print(person) # Output: {'name': 'John', 'age': 31, 'country': 'INDIA'}
.
'address': '123 M.G. Road'}
m
5.3.4 Deleting Key-Value Pairs
ru
To delete a key-value pair, use the del keyword with the key.
Fo
del person["address"]
print(person) # Output: {'name': 'John', 'age': 31, 'country': 'INDIA'}
ST
Be cautious when deleting key-value pairs, as Python will raise a KeyError if the key doesn't
exist. To avoid this, you can use the dictionary's pop() method, which removes the
key-value pair and returns the value. If the key doesn't exist, it returns a default value (if
R
specified) or None.
ht
if "age" in person:
print("Key exists")
else:
C
To loop through both keys and values, you can use the dictionary's items() method:
.
m
5.3.7 Dictionary Methods
Just like lists, dictionaries also come with built-in methods to make it easier to work with
ru
them. Below are some of the dictionary methods:
Fo
5.3.7.1 clear()
This method removes all items from the dictionary.
ST
person.clear()
print(person) # Output: {}
R
5.3.7.2 copy()
This method returns a copy of the dictionary.
ht
person_copy = person.copy()
ig
This static method returns a new dictionary with keys from the given iterable and all values
set to the provided value (defaults to None).
C
5.3.7.4 keys()
This method returns a view object containing the dictionary's keys.
5.3.7.5 values()
This method returns a view object containing the dictionary's values.
values = person.values()
print(values) # Output: dict_values(['John', 31, 'INDIA'])
5.3.7.6 items()
.
m
This method returns a view object containing a tuple for each key-value pair.
ru
items = person.items()
print(items) # Output: dict_items([('name', 'John'), ('age', 31),
('country', 'USA')])
5.3.7.7 popitem()
Fo
ST
This method removes and returns the last inserted key-value pair as a tuple. If the dictionary
is empty, it raises a KeyError.
item = person.popitem()
R
5.3.7.8 update([other])
ig
This method updates the dictionary with the key-value pairs from another dictionary or from
an iterable of key-value pairs. It overwrites the existing keys.
yr
There are several other dictionary methods available that you can explore.
For example, you could create a dictionary where the keys are numbers from 1 to 10, and
the values are the square of these numbers:
.
m
squares = {i: i ** 2 for i in range(1, 11)}
ru
print(squares) # Output: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49,
8: 64, 9: 81, 10: 100}
Fo
Ex. 2: Create a dictionary with selective keys
Suppose you have a list of words and you want to create a dictionary that stores the lengths
of the words, but only for words that are more than 3 letters long. You could accomplish this
ST
with a dictionary comprehension:
'zebra': 5}
C
In this case, the dictionary comprehension works by iterating over each word in the words
list. If the length of the word is more than 3, a new key-value pair is added to the dictionary,
with the key being the word itself and the value being the length of the word.
In this section, we've explored the core concepts and functionalities of dictionaries in Python.
We started with the basics of creating and accessing dictionary elements, followed by a
detailed look at various dictionary methods that allow us to add, remove, and manipulate
items. We've learned how to iterate over a dictionary, use conditional checks in our
dictionary operations, and leverage the flexibility of dictionaries in handling data.
We also delved into the world of dictionary comprehensions, a powerful Python feature that
But remember, like any other tool, dictionaries and their methods should be used judiciously.
Always consider the nature of your problem and the structure of your data to decide if a
dictionary is the best tool for the job.
With the knowledge we've gained here, we're now equipped to deal with many real-world
tasks involving structured data. Dictionaries, with their key-value pairs, often closely
resemble the data models we see in databases and APIs, so understanding them is a
significant step forward on your Python journey.
.
m
As we move forward, we'll now shift our focus to another fundamental data structure in
Python, the Tuple. Tuples, while similar to lists, come with their own unique set of properties
and uses. Let's continue our learning journey!
ru
Fo
5.4 Python Tuples
5.4.1 Introduction
ST
A Tuple in Python is similar to a list in that it is a sequence of elements. However, the key
difference is that while lists are mutable, tuples are immutable. This means that once a tuple
is created, it cannot be modified - you can't add, modify, or delete elements from a tuple.
R
This immutability makes tuples useful in situations where you need a constant set of values
and assurance that they will not change.
ht
print(fruits)
op
Like lists, tuples are also sequences, so you can access individual elements in a tuple using
indexing. Let's see an example:
Negative indexing works in the same way as it does with lists. If you want to access the last
.
m
fruits = ('apple', 'banana', 'cherry')
fruit1, fruit2, fruit3 = fruits
ru
print(fruit1)
print(fruit2)
Fo
print(fruit3)
We can use a for loop to iterate over the elements in a tuple. Here's an example:
ig
print(fruit)
op
apple
banana
cherry
This is the first part of our exploration into Python tuples. We'll be diving deeper into more
advanced aspects of tuples such as tuple methods and tuple comprehension in the next
section.
● count(): This method returns the number of times a specific value appears in the
tuple.
● index(): This method returns the index of the first occurrence of a specified value.
.
m
In this example, fruits.count('apple') returns 2 because 'apple' appears twice in the
tuple. fruits.index('cherry') returns 2 because the first occurrence of 'cherry' is at
ru
index 2.
Fo
5.4.6 Immutability of Tuples
Let's talk a bit more about the immutability of tuples. Since tuples are immutable, you might
think that they can't be modified at all. While it's true that you can't add or remove elements
ST
from a tuple, or change the existing elements, you can still modify the mutable objects
contained within the tuple.
tuple1[2][1] = 'cherry'
print(tuple1) # Output: (1, 2, ['apple', 'cherry'])
yr
In this example, even though the tuple itself is immutable, the list within the tuple is mutable
and can be modified.
op
So why might you choose to use a tuple instead of a list, given that lists have more features
and are more flexible?
Tuples are often used in situations where a statement or a user-defined function can safely
assume that the sequence of values will not change. For instance, the months of a year, or
the colors of a rainbow.
Tuples have the advantage of being more memory efficient than lists because they have
fewer built-in methods and their immutability allows Python to optimize resources devoted to
them.
Here's an example:
# Tuple Packing
.
m
fruit_tuple = ("apple", "banana", "cherry")
# Tuple Unpacking
ru
fruit1, fruit2, fruit3 = fruit_tuple
Fo
print(fruit1) # Output: apple
print(fruit2) # Output: banana
print(fruit3) # Output: cherry
ST
In this example, we first pack three strings into fruit_tuple. Then we unpack the values from
fruit_tuple into fruit1, fruit2, and fruit3.
R
Tuple unpacking can be useful in a variety of scenarios. For instance, we can use it to swap
the values of two variables:
ht
a = 5
ig
b = 10
a, b = b, a
op
print(a) # Output: 10
print(b) # Output: 5
C
In this example, we are using a tuple to swap the values of a and b without needing a
temporary variable.
In this example, numbers is not a tuple, but a generator object. You can convert this
generator into a tuple using the tuple() function.
And that wraps up our discussion on tuples in Python! We covered the creation and
manipulation of tuples, various tuple methods, the immutability of tuples, tuple packing and
unpacking, and the lack of tuple comprehension. Tuples are a fundamental data structure in
Python, and knowing how to work with them will serve you well as you continue your Python
.
journey.
m
Next, we will be exploring sets, another type of built-in data structure in Python.
ru
Fo
5.5 Python Sets
5.5.1 Introduction
ST
A set is an unordered collection of unique elements in Python. It is used to store multiple
items in a single variable. Sets are similar to lists and tuples, but unlike those data types,
sets do not maintain any specific order of the elements. Additionally, sets only contain
R
In Python, sets are defined by enclosing comma-separated elements within curly braces {}.
ht
For example:
ig
elements. Instead, we typically use sets for membership testing or performing set
operations.
5.5.3.1 Union
The union of two sets contains all the unique elements from both sets. In Python, we can
set1 = {1, 2, 3}
set2 = {2, 3, 4}
union_set = set1.union(set2)
print(union_set) # Output: {1, 2, 3, 4}
.
5.5.3.2 Intersection
m
The intersection of two sets contains the common elements present in both sets. We can
use the intersection() method or the & operator to perform the intersection operation.
ru
set1 = {1, 2, 3}
Fo
set2 = {2, 3, 4}
intersection_set = set1.intersection(set2)
print(intersection_set) # Output: {2, 3}
ST
# Using the & operator
intersection_set = set1 & set2
R
5.5.3.3 Difference
ht
The difference between two sets contains the elements present in the first set but not in the
second set. We can use the difference() method or the - operator to perform the
ig
difference operation.
yr
set1 = {1, 2, 3}
set2 = {2, 3, 4}
op
difference_set = set1.difference(set2)
print(difference_set) # Output: {1}
C
.
Sets have several built-in methods that allow us to perform various operations on sets. Here
m
are some of the commonly used set methods:
ru
5.5.4.1 add()
The add() method adds an element to the set. If the element is already present, it does not
Fo
add it again.
5.5.4.2 remove()
R
The remove() method removes a specific element from the set. If the element is not found,
it raises a KeyError.
ht
fruits.remove('banana')
print(fruits) # Output: {'apple', 'cherry'}
yr
5.5.4.3 discard()
op
The discard() method removes a specific element from the set. If the element is not found,
it does not raise any error.
C
5.5.4.4 pop()
The pop() method removes an arbitrary element from the set and returns it. Since sets are
unordered, there is no defined order in which elements are popped.
5.5.4.5 clear()
The clear() method removes all elements from the set, making it an empty set.
.
print(fruits) # Output: set()
m
These are just a few examples of the methods available for working with sets. You can
ru
explore more set methods in the Python documentation.
Fo
5.5.5 Set Comprehension
Similar to list comprehensions, Python also provides set comprehensions to create sets in a
ST
concise way. Set comprehensions use curly braces {} instead of square brackets []. Let's
see an example:
R
In this example, we use a set comprehension to create a set of squares of numbers from 0
to 4.
ig
Set comprehensions are a powerful tool for creating sets based on iterable objects, with the
yr
This concludes our detailed exploration of Python sets. Sets are versatile data structures
op
that offer unique features such as uniqueness and set operations. By understanding sets
and their methods, you can efficiently work with collections of unique elements in your
Python programs.
C
text = "It was the best of times, it was the worst of times"
frequency = {}
.
m
print(frequency)
ru
In this example, we first convert the given text into lowercase and replace the punctuation
with nothing. Then, we split the text by whitespace to get a list of words. After that, we count
Fo
the frequency of each word in the list using a dictionary.
new_course = 'Art'
ig
courses.append(new_course)
op
print(students)
In this example, we start with a dictionary that has student names as keys and a list of their
C
courses as values. We then iterate over the dictionary, adding a new course to each
student's list of courses.
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list2 = [5, 10, 15, 2, 20, 25]
print(list(common_elements))
In this example, we start with two lists of numbers. We convert each list to a set, which
automatically removes any duplicates. Then, we find the intersection of the two sets (i.e., the
common elements) using the & operator. Finally, we convert the resulting set back to a list for
printing.
.
m
4. Calculating Average Grades
ru
grades = {
'Alice': [85, 90, 92],
Fo
'Bob': [78, 88, 91],
'Charlie': [80, 85, 88],
'David': [92, 95, 98]
ST
}
In this program, we have a dictionary with student names as keys and a list of their grades
as values. We calculate the average grade for each student by summing the grades and
dividing by the number of grades.
ig
("Donuts", 12)]
grocery_bag = {}
C
print(grocery_bag)
This script takes a list of tuples where each tuple represents an item and its quantity. It then
transforms this list into a dictionary for easier access to each item and its quantity.
print(character_frequency)
In this example, we count the frequency of each character in the text string. We use a
.
dictionary to track the counts, with each character as a key and its count as the
m
corresponding value.
ru
Fo
ST
R
ht
ig
yr
op
C
In programming, functions serve as the building blocks of code. The concept of a function is
borrowed from mathematics, where a function maps input to output according to some rule.
Similarly, in programming, a function is a named sequence of statements that performs a
desired operation. This operation is specified in a function definition.
The idea of using functions or subroutines in computing dates back to the earliest
.
m
programming languages in the 1950s and 60s. The advent of procedural programming
further emphasized the use of functions, as they allowed for code reuse and abstraction,
making complex software systems more manageable and modular.
ru
Functions were created to improve the modularity of program code and to minimize
Fo
repetition. Through functions, we can write reusable pieces of code. These are
self-contained and can be plugged into different programs, making the code cleaner, more
efficient, and easier to understand.
ST
6.2 Python Functions and Their Syntax
R
In Python, functions are defined using the def keyword followed by the function name and
parentheses (). The code block within every function is indented, which starts with a colon
(:) and is followed by the function's body. Here's the general syntax:
ht
def function_name(parameters):
ig
"""docstring"""
# statements
yr
return expression
op
● parameters (or arguments): These are optional and are input to the function. They
are specified within the parentheses.
● :: This is used to mark the end of the function header.
● docstring: Short for documentation string, it's optional and is used to describe what
the function does.
● statements: The function body where operations are performed.
● return: This is optional. A function may or may not return a value.
Here, greet is the function name, name is the parameter, and the statement within the
function greets the person.
.
m
Parameters are the values that a function expects to receive when it is called, defined in the
function header. When you call a function, the values you pass in are known as arguments.
ru
In Python, there are several types of parameters:
Fo
● Positional Parameters: These are read in order from left to right.
● Keyword Parameters: These allow you to specify the parameter's value by name.
● Default Parameters: If no argument is given during the function call, these
ST
parameters use a default value.
arguments. Though they are sometimes used interchangeably, they do not mean exactly the
same thing.
6.4.1 Parameters
Parameters are the names used when defining a function. They are placed inside the
parentheses of the function definition and represent the inputs that the function will accept
when it is called. For example:
Here, a and b are parameters of the function add_numbers. They serve as placeholders for
actual values that will be used when the function is called.
6.5.2 Arguments
Arguments, on the other hand, are the actual values that are passed to a function when it is
called. Each argument corresponds to a parameter in the function definition. For example:
.
result = add_numbers(5, 3)
m
Here, 5 and 3 are arguments that are being passed to the function add_numbers.
ru
In short, parameters are the variables in a function definition, and arguments are the values
Fo
put into those variables when the function is called.
syntax:
ht
def function_name(parameters):
# code block
return result
ig
yr
In the most basic form, a function can return a simple value. Let's consider a function that
returns the square of a number:
C
def square(n):
"""Returns the square of a number"""
return n**2
print(square(5)) # Output: 25
In the function above, the return statement returns the square of the number n. When we
call square(5), the output is 25.
Python functions can return multiple values. This is typically done by packing the values to
be returned into a tuple, which is then unpacked by the calling code. Here is an example:
def get_info():
"""Return a tuple of information"""
name = "Alice"
age = 25
city = "New York"
return name, age, city
.
m
info = get_info()
print(info) # Output: ('Alice', 25, 'New York')
ru
This function returns three values, which are packaged into a tuple. We can also use tuple
Fo
unpacking to assign these values to separate variables:
The return statement, when executed, immediately exits the function, regardless of any
remaining statements in the function. Any code written after the return statement in a
ig
For instance:
op
def return_test(n):
"""Returns a string and ignores the rest of the function"""
if n > 0:
C
In this function, the print statement is never executed because the function execution is
stopped once it hits the return statement.
.
functions (or non-local scope) will be checked, starting from the innermost function
m
and extending outwards.
● Global: Names assigned at the top-level of a module file, or declared global in a
ru
function in the file. If a variable is not found in the local and enclosing scopes, Python
will check the global scope, which includes any variable defined at the module level
or declared global with the global keyword inside a function.
Fo
● Built-in: Names preassigned in the built-in names module. These are the built-in
function names in Python (like abs(), sum(), print(), etc.). If Python cannot find
the variable in the local, enclosing, or global scopes, it will check the built-in scope.
ST
Python checks these scopes in the order LEGB whenever a variable is referenced.
A variable defined inside a function has a local scope. It is accessible from the point at which
it is defined until the end of the function, and exists for as long as the function is executing.
ht
def local_example():
local_var = "I'm a local variable"
yr
print(local_var)
In this example, local_var is defined within local_example and only accessible within the
function.
Non-local (or enclosing) scope covers variables defined in an enclosing function. In other
words, if a function is nested within another function, it can access variables from the outer
(or enclosing) function.
def inner_func():
print(outer_var) # It has access to outer_var
inner_func()
.
m
6.6.3 Global Scope
ru
A variable defined outside all function definitions is a global variable and has a global scope.
It is accessible from any point in the code.
Fo
global_var = "I'm a global variable"
def global_example():
ST
print(global_var) # It can access global_var
In this example, global_var is defined globally and is accessible both inside and outside of
ht
global_example.
ig
keyword.
op
def modify_global():
C
global global_var
global_var = "I have been changed!"
modify_global()
print(global_var) # Output: I have been changed!
def inner():
nonlocal outer_var
outer_var = "I'm changed in inner function"
inner()
print(outer_var) # Output: I'm changed in inner function
.
outer()
m
By understanding Python's scope rules, you can avoid many common errors related to
ru
variable assignment and access. Remember the LEGB rule and you'll know where your
variables can and cannot be used.
Fo
6.7 Documenting Python Functions
ST
Properly documenting your code is an essential part of programming. For Python functions,
this is usually done through what's known as a docstring, a type of comment used to explain
the purpose of a function and how it should be used.
R
A docstring is a string literal that occurs as the first statement in a module, function, class, or
method definition. It becomes the __doc__ special attribute of that object. Docstrings are
written between triple quotes """ to span multiple lines. Here's an example:
ig
In the example above, the docstring is This function adds two numbers and returns
the result. It briefly explains what the function does.
C
There are two primary ways to access the docstrings of a Python function:
● The .__doc__ attribute: This attribute is used to retrieve the docstring from a
function.
● The help() function: This function is used to display the docstring along with some
other helpful information such as function signature, module name, and more.
help(add_numbers)
The output will include the function's signature, its docstring, and where it was defined.
.
6.7.3 Writing Effective Docstrings
m
Docstrings should provide a clear, brief overview of what the function does. For larger, more
complicated functions, they might also explain the function's arguments, return values, and
ru
any exceptions that it might raise. The PEP 257
(https://www.python.org/dev/peps/pep-0257/) guide provides a good guide on how to write
Fo
effective docstrings.
Parameters:
ht
Returns:
int or float: The sum of the two numbers
yr
"""
return a + b
op
This docstring not only explains what the function does but also describes its parameters,
their expected types, and the return value.
C
By writing effective docstrings, you can make your code much easier to understand and use,
both for others and for your future self.
def sum_numbers(*args):
"""This function sums any number of input arguments."""
.
return sum(args)
m
print(sum_numbers(1, 2, 3, 4)) # Output: 10
print(sum_numbers(10, 20)) # Output: 30
ru
In this function, *args can accept any number of arguments, and the function will return their
Fo
sum.
example:
ht
def print_student_info(**kwargs):
"""This function prints student information in key-value pairs."""
for key, value in kwargs.items():
ig
print(f"{key}: {value}")
yr
In this example, the function accepts any number of keyword arguments and prints them out
in key-value pairs.
C
In this function, *args is used to sum the positional arguments, and **kwargs is used to print
the keyword arguments.
.
1. Standard positional parameters
m
2. *args
3. Keyword parameters
ru
4. **kwargs
Here's an example:
Fo
def ordered_arguments(a, b, *args, c=10, d=20, **kwargs):
print(a, b, args, c, d, kwargs)
ST
ordered_arguments(1, 2, 3, 4, 5, c=30, name="Alice", age=20)
R
In this example, 1 and 2 are assigned to the positional parameters a and b. 3, 4, and 5 are
grouped together into args. The keyword parameter c is given a new value of 30, d uses its
default value of 20, and the remaining keyword arguments are grouped together into
ht
kwargs.
ig
Understanding and using *args and **kwargs can make your functions more flexible and
reusable. They allow your functions to work with a variable number of arguments, making
yr
Functions
C
Just as *args and **kwargs allow for variable numbers of arguments in function definitions,
the same operators can be used in function calls to unpack arguments from sequences and
dictionaries. This is known as argument unpacking.
numbers = [1, 2, 3]
print(add_three_numbers(*numbers)) # Output: 6
In the example above, the list numbers is unpacked into the three arguments for the
add_three_numbers function using the * operator.
.
function call.
m
def print_student_info(name, age):
ru
print(f"Name: {name}, Age: {age}")
Fo
student_info = {"name": "Alice", "age": 20}
print_student_info(**student_info) # Output: Name: Alice, Age: 20
ST
In this example, the dictionary student_info is unpacked into the keyword arguments for
the print_student_info function using the ** operator.
Both * and ** can be used in a single function call to unpack both a sequence and a
dictionary.
ht
In this example, info_sequence is unpacked into the positional arguments and info_dict
is unpacked into the keyword argument for the student_info function.
This feature of argument unpacking in Python makes your function calls flexible and clean,
especially when working with sequences and dictionaries of data.
.
m
Here is the syntax for a lambda function:
ru
lambda arguments: expression
Fo
Here's an example of a simple lambda function that adds two numbers:
add = lambda a, b: a + b
ST
print(add(5, 3)) # Output: 8
In this example, a and b are the arguments, and a + b is the expression. The function adds
R
Lambda functions are used when you need a function for a short period of time. This is
commonly used when you want to pass a function as an argument to higher-order functions,
ig
Lambda functions make your code concise and can be extremely useful in a variety of
situations. However, they are limited in their complexity and shouldn't be used for more
op
Lambda functions are often used with built-in functions like filter(), map(), and reduce().
● filter(function, sequence): This function offers an elegant way to filter out all
the elements of a sequence. The function function needs to return a Boolean value.
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # Output: [2, 4, 6]
● map(function, sequence): This function applies the function to all the elements of
the sequence. It returns a new list with the elements changed by the function.
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, numbers))
print(squares) # Output: [1, 4, 9, 16, 25]
In this example, the lambda function squares each number in the list.
.
● reduce(function, sequence): This function continually applies the function to the
m
sequence and returns a single value. Note that reduce() is in the functools module.
ru
from functools import reduce
Fo
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(product) # Output: 120
ST
In this example, the lambda function calculates the product of all numbers in the list.
Lambda functions are a powerful feature of Python that allow you to create quick, short-lived
R
functions for a variety of tasks. While they can be incredibly useful, it's important to
remember that they are limited in complexity and should be used sparingly to ensure your
ht
add = lambda a, b: a + b
print(add(5, 3)) # Output: 8
C
multiply = lambda a, b: a * b
print(multiply(5, 3)) # Output: 15
is_even = lambda x: x % 2 == 0
print(is_even(4)) # Output: True
square = lambda x: x ** 2
print(square(4)) # Output: 16
.
m
6. Sorting a list of tuples by the second element:
ru
pairs = [(1, 'one'), (3, 'three'), (2, 'two')]
pairs.sort(key=lambda pair: pair[1])
Fo
print(pairs) # Output: [(1, 'one'), (3, 'three'), (2, 'two')]
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
yr
numbers = [1, 2, 3, 4, 5]
max_number = reduce(find_max, numbers)
print(max_number) # Output: 5
print(abs(-5)) # Output: 5
2. all(iterable): Returns True if all elements of the iterable are true (or if the iterable
.
is empty).
m
print(all([True, False, True])) # Output: False
ru
3. any(iterable): Returns True if any element of the iterable is true. If the iterable is
Fo
empty, return False.
7. chr(i): Return the string representing a character whose Unicode code point is the
integer i.
9. divmod(a, b): Take two numbers as arguments and return a pair of numbers (a
tuple) consisting of their quotient and remainder when using integer division.
.
m
print(i, v) # Output: 1 a, 2 b, 3 c
ru
11. filter(function, iterable): Construct an iterator from elements of iterable for
which function returns true.
Fo
numbers = [1, 2, 3, 4, 5]
evens = filter(lambda x: x % 2 == 0, numbers)
print(list(evens)) # Output: [2, 4]
ST
12. float([x]): Convert a string or a number to floating point.
R
13. hex(x): Convert an integer number to a lowercase hexadecimal string prefixed with
“0x”.
ig
14. input([prompt]): Read a line from input, convert it to a string (stripping a trailing
op
print(int(2.5)) # Output: 2
16. len(s): Return the length of an object. The argument may be a sequence or a
collection.
18. max(iterable): Return the largest item in an iterable or the largest of two or more
arguments.
.
m
print(max([1, 2, 3])) # Output: 3
ru
19. min(iterable): Return the smallest item in an iterable or the smallest of two or
more arguments.
Fo
print(min([1, 2, 3])) # Output: 1
23. sorted(iterable): Return a new sorted list from the items in iterable.
C
25. sum(iterable): Sums start and the items of an iterable from left to right and returns
the total.
26. zip(*iterables): Makes an iterator that aggregates elements from each of the
iterables. Returns an iterator of tuples, where the i-th tuple contains the i-th element
from each of the argument sequences or iterables.
numbers = [1, 2, 3]
letters = ['a', 'b', 'c']
print(list(zip(numbers, letters))) # Output: [(1, 'a'), (2, 'b'), (3,
'c')]
.
m
27. type(object): Returns the type of the object.
ru
print(type(123)) # Output: <class 'int'>
Fo
28. set([iterable]): Returns a new set object, optionally with elements taken from
iterable.
ST
print(set([1, 2, 2, 3, 3, 3])) # Output: {1, 2, 3}
29. ord(c): Given a string representing one Unicode character, return an integer
R
print(ord('a')) # Output: 97
ht
30. id(object): Return the “identity” of an object. This is an integer which is guaranteed
ig
a = 'Hello'
print(id(a)) # Output: Some id value, like 139860847423824
op
These functions cover a wide range of tasks, allowing you to write more efficient and
readable code. They are versatile and can be used in many different contexts. Remember,
C
Python's built-in functions are your friend - they are there to make your life easier, so you do
not have to reinvent the wheel every time.
contacts = []
.
m
def add_contact():
name = input("Enter the name of the contact: ")
ru
phone = input("Enter the phone number of the contact: ")
email = input("Enter the email address of the contact: ")
contact = {
Fo
'name': name,
'phone': phone,
'email': email
ST
}
contacts.append(contact)
print("Contact added successfully.")
R
def view_contacts():
if not contacts:
ht
print(f"Phone: {contact['phone']}")
print(f"Email: {contact['email']}")
op
print("-------------------------")
def search_contacts():
C
if not found_contacts:
print("No matching contacts found.")
else:
print("Matching contacts:")
def update_contact():
name = input("Enter the name of the contact to update: ")
for contact in contacts:
if contact['name'].lower() == name.lower():
phone = input("Enter the updated phone number: ")
.
email = input("Enter the updated email address: ")
m
contact['phone'] = phone
contact['email'] = email
ru
print("Contact updated successfully.")
return
Fo
print("Contact not found.")
def delete_contact():
ST
name = input("Enter the name of the contact to delete: ")
for contact in contacts:
if contact['name'].lower() == name.lower():
R
contacts.remove(contact)
print("Contact deleted successfully.")
return
ht
if choice == '1':
add_contact()
elif choice == '2':
view_contacts()
elif choice == '3':
.
m
ru
6.12.2 To-Do List Manager
Fo
A program that helps the user manage their tasks. The user can add new tasks, mark tasks
as completed, view the list of tasks, and remove completed tasks.
ST
# To-Do List Manager
tasks = []
R
def add_task():
task = input("Enter a new task: ")
tasks.append(task)
ht
def view_tasks():
if not tasks:
yr
def mark_completed():
view_tasks()
task_number = int(input("Enter the task number to mark as completed:
"))
if 1 <= task_number <= len(tasks):
task = tasks[task_number - 1]
print(f"Task '{task}' marked as completed.")
tasks.remove(task)
def remove_completed():
completed_tasks = [task for task in tasks if
task.endswith("(Completed)")]
if not completed_tasks:
print("No completed tasks found.")
else:
print("Completed Tasks:")
for index, task in enumerate(completed_tasks, start=1):
.
print(f"{index}. {task}")
m
remove_option = input("Do you want to remove all completed
ru
tasks? (yes/no): ")
if remove_option.lower() == "yes":
tasks[:] = [task for task in tasks if not
Fo
task.endswith("(Completed)")]
print("Completed tasks removed successfully.")
elif remove_option.lower() == "no":
ST
print("No completed tasks were removed.")
else:
print("Invalid option.")
R
print("5. Exit")
op
if choice == '1':
C
add_task()
elif choice == '2':
view_tasks()
elif choice == '3':
mark_completed()
elif choice == '4':
remove_completed()
elif choice == '5':
print("Thank you for using the To-Do List Manager. Goodbye!")
break
.
# Inventory Management System
m
inventory = {}
ru
def add_product():
product_id = input("Enter the product ID: ")
Fo
if product_id in inventory:
print("Product already exists in the inventory.")
return
ST
name = input("Enter the product name: ")
quantity = int(input("Enter the product quantity: "))
price = float(input("Enter the product price: "))
R
product = {
'name': name,
ht
'quantity': quantity,
'price': price
ig
}
inventory[product_id] = product
yr
def update_product():
op
return
product = {
'name': name,
def view_inventory():
if not inventory:
print("Inventory is empty.")
else:
print("Inventory:")
.
for product_id, product in inventory.items():
m
print(f"Product ID: {product_id}")
print(f"Name: {product['name']}")
ru
print(f"Quantity: {product['quantity']}")
print(f"Price: {product['price']}")
print("-------------------------")
def generate_report():
if not inventory:
Fo
ST
print("Inventory is empty.")
else:
print("Inventory Report:")
R
print(f"Quantity: {product['quantity']}")
print(f"Price: {product['price']}")
print(f"Total Value: {product['quantity'] *
ig
product['price']}")
print("-------------------------")
yr
while True:
print("Inventory Management System")
print("1. Add Product")
C
if choice == '1':
add_product()
elif choice == '2':
.
m
ru
6.12.4 Student Grade Calculator
A program that calculates and stores the grades of a class. The program allows the user to
Fo
enter the names and scores of students, calculate their average grades, display the highest
and lowest grades, and sort the student list based on grades.
ST
# Student Grade Calculator
students = []
R
def add_student():
name = input("Enter the student's name: ")
scores = []
ht
for i in range(3):
score = float(input(f"Enter score {i+1}: "))
ig
scores.append(score)
student = {
yr
'name': name,
'scores': scores
}
op
students.append(student)
print("Student added successfully.")
C
def calculate_average(scores):
total = sum(scores)
return total / len(scores)
def calculate_highest_lowest():
highest_score = float('-inf')
lowest_score = float('inf')
highest_student = ''
lowest_student = ''
.
m
def view_students():
if not students:
ru
print("No students found.")
else:
print("Students:")
Fo
for student in students:
name = student['name']
scores = student['scores']
ST
average = calculate_average(scores)
print(f"Name: {name}")
print(f"Scores: {scores}")
R
print(f"Average: {average}")
print("-------------------------")
ht
def sort_students():
sorted_students = sorted(students, key=lambda x:
calculate_average(x['scores']), reverse=True)
ig
name = student['name']
scores = student['scores']
op
average = calculate_average(scores)
print(f"Name: {name}")
print(f"Scores: {scores}")
C
print(f"Average: {average}")
print("-------------------------")
if choice == '1':
add_student()
elif choice == '2':
view_students()
elif choice == '3':
highest_student, highest_score, lowest_student, lowest_score =
calculate_highest_lowest()
.
print(f"Highest Average: {highest_student} - {highest_score}")
m
print(f"Lowest Average: {lowest_student} - {lowest_score}")
elif choice == '4':
ru
sort_students()
elif choice == '5':
print("Thank you for using the Student Grade Calculator.
Fo
Goodbye!")
break
else:
ST
print("Invalid choice. Please try again.")
R
paragraph, and the program should output a dictionary containing each unique word and its
frequency in the text.
ig
.
sorted_word_freq = sorted(word_freq.items(), key=lambda x: x[1],
m
reverse=True)
ru
# Display the top 5 most frequent words
print("Top 5 Most Frequent Words:")
for word, freq in sorted_word_freq[:5]:
Fo
print(f"{word}: {freq}")
ST
R
ht
ig
yr
op
C
.
m
more robust and reliable, and improve your productivity as a programmer.
A good debugger helps to identify the root cause of an issue by allowing you to inspect the
ru
state of the program at various stages of its execution. This can involve examining the
values of variables, the flow of control, and the call stack.
Fo
7.2 Python Exceptions
In Python, errors detected during execution are called "exceptions". They are not
ST
unconditionally fatal, but by default, they cause the program to terminate. Exceptions can be
handled in Python code using try and except blocks. When the code in the try block
encounters an error, control is passed to the corresponding except block, where you can
R
.
● AttributeError: Raised when an attribute reference or assignment fails.
m
x = 10
ru
x.append(6) # 'int' object has no attribute 'append'
Fo
● TypeError: Raised when an operation or function is applied to an object of
inappropriate type.
ST
'2' + 2 # unsupported operand types for +
R
● FileNotFoundError: Raised when trying to open a file that does not exist.
yr
with open('non_existent_file.txt') as f:
op
print(f.read())
C
import math
● RuntimeError: Raised when an error is detected that doesn’t fall in any of the other
categories.
.
m
def func():
print("Hello World") # expected an indented block
ru
Fo
● StopIteration: Raised by built-in function next() and an iterator‘s __next__()
method to signal that there are no further items produced by the iterator.
ST
my_list = iter([1, 2, 3])
print(next(my_list))
print(next(my_list))
print(next(my_list))
R
print(next(my_list)) # StopIteration
ht
def func():
print(x)
x = 10
op
These are just a few examples of exceptions that can be raised in Python
(https://docs.python.org/3/library/exceptions.html). When these occur, Python provides a
traceback, which can be used to determine where the error occurred and what function calls
led up to the error.
By understanding these exceptions and learning how to handle them properly, you can write
more robust Python programs and become a more effective programmer.
What's important at this stage is to understand that these exceptions exist and knowing how to
handle them can lead to more robust code. They provide important clues when something goes
wrong in your program. Reading and understanding the traceback of these exceptions can help you
locate the source of the problem.
Remember, encountering errors and exceptions is a normal part of the programming process,
.
regardless of your skill level. Even seasoned programmers deal with bugs in their code. The key is
m
understanding how to effectively debug these issues, and the first step in that process is
understanding the exceptions that Python might throw at you.
ru
As you progress further in your Python programming journey, be sure to revisit this chapter and
others as a handy reference.
Fo
7.3 Handling Exceptions in Python: try/except
ST
The Python language provides a simple yet powerful way of handling exceptions using the
try and except keywords.
When the code inside the try block encounters an error, control is passed to the
R
corresponding except block, where you can handle the error or output a more user-friendly
error message.
ht
Example 1:
yr
try:
result = 10 / 0
op
except ZeroDivisionError:
print("You can't divide by zero!")
C
In this example, the code tries to divide a number by zero, which raises a
ZeroDivisionError. The except block catches this error and prints a friendly message
instead of letting the program crash.
Example 2:
try:
numbers = [1, 2, 3]
print(numbers[5])
In this example, the code tries to access an index that doesn't exist in the list, raising an
IndexError. The except block catches this error and prints an informative message.
Example 3:
try:
with open('non_existent_file.txt') as f:
.
print(f.read())
m
except FileNotFoundError:
print("That file was not found!")
ru
In this case, the code attempts to open a file that doesn't exist, raising a
FileNotFoundError. The except block catches this error and informs the user.
Fo
7.3.1 More Advanced Exception Handling: try/except/else/finally
ST
For more sophisticated exception handling, Python provides the
try/except/else/finally construct. Here's what each block means:
● finally: This block is always executed no matter what, whether an exception was
raised or not, even if an uncaught exception or a return/break/continue statement
ig
Example 1:
op
try:
C
result = 10 / 2
except ZeroDivisionError:
print("You can't divide by zero!")
else:
print("The division succeeded!")
finally:
print("End of program.")
In this example, no exception is raised, so the else block is executed, and then the finally
block is executed.
try:
numbers = [1, 2, 3]
print(numbers[5])
except IndexError:
print("That index is not in the list!")
else:
print("Index found in list!")
finally:
.
print("End of program.")
m
In this example, an IndexError is raised, so the except block is executed, and then the finally
ru
block is executed.
Fo
Example 3:
try:
ST
with open('non_existent_file.txt') as f:
print(f.read())
except FileNotFoundError:
print("That file was not found!")
R
else:
print("File found and read successfully!")
finally:
ht
print("End of program.")
ig
In this case, a FileNotFoundError is raised, so the except block is executed, and then the
finally block is executed.
yr
exceptions in Python,
While Python provides a number of built-in exceptions that can handle most common error
scenarios, there may be times when you need to generate exceptions based on your
application-specific conditions. This is where the raise keyword comes into play.
The raise keyword allows you to trigger exceptions in your code manually, enabling you to
react to potential issues that are specific to your application's requirements. This is a
powerful tool for ensuring that your programs behave as expected under all conditions.
First, let's look at how we can use the raise keyword to trigger built-in exceptions.
For example, imagine you're building a calculator app and you want to prevent users from
dividing by zero. You could use the raise keyword to throw a ZeroDivisionError
exception when the denominator is zero, as shown in this function:
.
m
else:
return num1 / num2
ru
In this example, when you call divide(10, 0), the function will raise a
ZeroDivisionError with the message "You can't divide by zero!"
To define a custom exception, you can create a new class that inherits from the built-in
R
class ValueTooHighError(Exception):
ht
pass
ig
class ValueTooLowError(Exception):
def __init__(self, message, value):
yr
self.message = message
self.value = value
op
In this code, we've defined two new exception types: ValueTooHighError and
ValueTooLowError. The ValueTooLowError exception includes a custom constructor
C
(__init__) that accepts additional arguments (message and value), which are then stored
as instance variables.
Now, you can use these custom exceptions in your code using the raise keyword:
def test_value(x):
if x > 100:
raise ValueTooHighError("Value is too high.")
if x < 5:
raise ValueTooLowError("Value is too low.", x)
.
m
In summary, the raise keyword is a powerful tool for handling errors and enforcing
constraints in your Python programs. By using it effectively, you can make your programs
ru
more robust and easier to debug.
Fo
Note:
In the previous examples, you saw how we can create custom exceptions by defining new classes
that inherit from the built-in Exception class. However, if you're not yet familiar with the concept of
ST
classes and object-oriented programming, don't worry. The understanding of these examples is not
crucial at this point.
We will delve into the topic of classes, objects, and object-oriented programming in Python in the
R
upcoming chapters. For now, it's enough to understand that a class is a blueprint for creating
objects (specific data structures), and that we can create our own types of exceptions by making
new classes that inherit from the built-in Exception class.
ht
When we get to the chapter on classes, we will revisit this topic and these examples will make
much more sense. For now, just understand that Python allows us to create our own exceptions
that we can raise in our programs using the raise keyword, which can be useful for handling error
ig
conditions specific to our applications. The details of how this is done will become clearer as you
progress in your understanding of Python.
yr
Sometimes reading error messages or print statements isn't enough to understand what's
going wrong with your code. In such cases, the Python Debugger, or PDB, can be an
invaluable tool. PDB allows you to interactively step through your code, line by line,
C
PDB is a part of Python's standard library and doesn't require any additional installation. It
provides various commands to help in debugging like setting breakpoints, stepping through
the code, inspecting variables, and changing variable values.
import pdb
.
mydict = {}
m
add_to_list_in_dict(mydict, "mylist", "myelement")
ru
In this example, we add a call to pdb.set_trace() where we want to start the debugging.
When Python executes this line, it'll start a pdb debugging session.
Fo
7.5.2 PDB commands
Once the pdb prompt is displayed, you can use a variety of commands to navigate through
ST
your code. Here are some of the most commonly used pdb commands:
● p(rint): Evaluate the expression in the current context and print its value.
yr
> /path/to/your/script.py(7)add_to_list_in_dict()
-> thedict[listname].append(element)
(Pdb) p thedict
C
{'mylist': []}
(Pdb) n
> /path/to/your/script.py(6)add_to_list_in_dict()
-> pdb.set_trace()
(Pdb) p thedict
{'mylist': ['myelement']}
(Pdb) c
In this example:
.
m
example:
ru
import pdb
def buggy_func(x):
Fo
return 1.0 / x
try:
ST
buggy_func(0)
except ZeroDivisionError:
pdb.post_mortem()
R
In summary, PDB is a powerful tool for Python debugging. By allowing you to step through
your code interactively and inspect variables at any point, PDB provides a deeper
ig
understanding of your code's execution flow and helps you pinpoint and fix bugs more
efficiently.
yr
op
C
.
m
found them a bit overwhelming, worry not! By the end of this chapter, you'll have a solid
understanding of these concepts and you'll be comfortable using them in your Python
programming journey.
ru
To ensure a thorough understanding of object-oriented programming in Python, we will cover
Fo
the following topics in this chapter:
Each section will build upon the last, starting with the basics and gradually delving into more
yr
advanced topics. By the end of this chapter, you'll be well-equipped to utilize the power of
object-oriented programming in Python for your coding projects.
op
Let's start with an introduction to the concept of object-oriented programming, understand its
historical context, significance, and how it compares with the procedural style of
C
.
m
8.1.2 The Concept of Classes and Objects
ru
A class is a blueprint for creating objects (a particular data structure), providing initial
values for state (member variables or attributes), and implementations of behavior
(member functions or methods). The user-defined objects are created using the class
Fo
structure. This is similar to the way a building blueprint describes how to construct a building,
and the buildings themselves are the objects.
ST
An object is an encapsulation of variables and functions into a single entity. Objects get their
variables and functions from classes. Classes are essentially a template to create your
objects.
R
class MyClass:
variable = "This is a class variable"
ig
def function(self):
print("This is a message inside the class.")
yr
my_object = MyClass()
op
In the example above, MyClass is a class with a class variable variable and a method
function. We create an object my_object using the MyClass definition. We can then
C
● Modularity for easier troubleshooting: When a problem occurs in OOP, you know
exactly where to look. That's because, in OOP, data type is tied to the data itself.
● Reuse of code through inheritance: Suppose that in addition to your Car object,
one colleague needs a RaceCar object, and another needs a Limousine object.
As a result of these advantages, OOP is used in a wide range of areas including web and
desktop applications, databases, AI, game development, and many more.
.
m
Object-oriented programming is a major paradigm, and it forms the basis for many modern
programming languages. Understanding OOP will give you an essential skill for today's
programming environment.
ru
8.2 Classes and Objects in Python
An object is created using the constructor of the class. This object will then be called the
R
instance of the class. You can create as many objects for a class as you need.
ht
class MyClass:
x = 5
ig
p1 = MyClass()
print(p1.x) # output: 5
yr
MyClass.
Defining a class in Python is simple and straightforward. You use the keyword class to define
a class. Here's a simple class definition:
class MyClass:
x = 5
In this example, we've created a class MyClass that has one attribute x.
p1 = MyClass()
.
m
class MyClass:
ru
x = 5
def hello(self):
Fo
print("Hello, I am a method of this class!")
p1 = MyClass()
ST
p1.hello() # output: Hello, I am a method of this class!
In this example, hello is a method of MyClass. Note that all methods must take at least one
R
The __init__ method is a special method that gets called when a new object is created
from a class. It allows the class to initialize attributes of the class.
ig
class MyClass:
yr
def __init__(self):
self.x = 5
op
p1 = MyClass()
print(p1.x) # output: 5
C
In this example, __init__ method is initializing x for the object being created. The self
keyword represents the instance of the class and is automatically passed as the first
parameter when a class's method is called.
class MyClass:
class_var = "I am a class variable!"
.
m
print(p1.class_var) # output: I am a class variable!
print(p2.class_var) # output: I am a class variable!
ru
print(p1.instance_var) # output: I belong to p1
print(p2.instance_var) # output: I belong to p2
Fo
In this example, class_var is a class variable shared by all instances, while instance_var
is specific to each instance.
ST
Classes and objects are a fundamental concept in Python's object-oriented programming.
They provide structure and reusable code and are used in almost all Python applications.
R
operations.
class BankAccount:
# Class variable - applicable to all instances
op
interest_rate = 0.05
.
# Customer Class Definition
m
class Customer:
def __init__(self, name, bank_account):
ru
self.name = name
self.bank_account = bank_account
Fo
# Instance method to deposit money
def deposit_money(self, amount):
self.bank_account.deposit(amount)
ST
print(f"{amount} deposited into account
{self.bank_account.account_number}")
R
{self.bank_account.balance}, Interest:
{self.bank_account.calculate_interest()}")
C
● Class and object definition: BankAccount and Customer are classes, account and
customer are objects.
● Use of the __init__ method to initialize object attributes.
● Instance variables (self.account_number and self.balance) and class variables
(interest_rate)
● Instance methods (deposit, withdraw, calculate_interest)
● Object interaction: Customer objects interact with BankAccount objects,
demonstrating the power of object-oriented programming.
.
m
You can run this program in your Python environment, try different operations, and see the
output.
ru
8.3 Inheritance and Polymorphism
Fo
8.3.1 Concept of Inheritance, Subclasses, and Superclasses
Inheritance is a key principle of object-oriented programming that allows one class to inherit
ST
the properties and methods of another class. This leads to code reusability and a
hierarchical structure between classes. The class from which properties and methods are
inherited is called the superclass or parent class, and the class that inherits these properties
and methods is called the subclass or child class.
R
For example, consider a Bird class and a Penguin class. All birds have certain
characteristics, like wings and the ability to fly. However, a penguin is a special kind of bird
ht
that cannot fly. This kind of relationship can be represented through inheritance: Bird would
be the superclass, and Penguin would be the subclass.
ig
Python allows inheritance through a simple syntax. When defining a subclass, you include
the superclass in parentheses in the class definition:
op
class Bird:
def can_fly(self):
C
return True
class Penguin(Bird):
def can_fly(self):
return False
Here, Penguin is a subclass of Bird and has overridden the can_fly method from the Bird
class.
In the example above, the Penguin class overrides the can_fly method from the Bird
class. When called on a Penguin instance, it will return False instead of True.
.
This can be useful when the subclass method wants to extend rather than entirely replace
m
the superclass method.
ru
class Bird:
def __init__(self):
self.can_fly = True
class Penguin(Bird):
def __init__(self):
Fo
ST
super().__init__() # calls the __init__ method of Bird
self.can_fly = False
R
In this example, Penguin calls the __init__ method of Bird using super() before setting
can_fly to False.
ht
superclasses:
yr
class Bird:
can_fly = True
op
class Swimmer:
can_swim = True
C
Here, Penguin is a subclass of both Bird and Swimmer. It inherits properties from both
classes but overrides the can_fly property from Bird.
Inheritance and polymorphism are powerful tools for creating reusable, organized, and
logical code structures in object-oriented programming.
.
m
def display_user_details(self):
print(f'Name: {self.name}, Email: {self.email}')
ru
# Class Definition for Student (Inherited from User)
class Student(User):
Fo
def __init__(self, name, email, student_id):
super().__init__(name, email) # Calls the init method of base
class
ST
self.student_id = student_id
class
print(f'Student ID: {self.student_id}')
ht
self.subject = subject
super().display_user_details()
print(f'Subject: {self.subject}')
C
.
admin.display_user_details()
m
In this program, Student, Teacher, and Administrator are all subclasses of User, and
ru
they each override the display_user_details method to include their unique details.
Fo
In addition, they each use super() to call the User (superclass) version of
display_user_details before adding their unique details. This illustrates how subclasses
can inherit from a superclass, override methods, and use super() to call superclass
methods.
ST
8.4 Special (Dunder) Methods
R
For example:
op
str() function on our object or when we try to print our object. It's meant to provide a
"user-friendly" output describing the object.
● __repr__(self): This is similar to __str__, but should provide more detailed
output. It's meant to be unambiguous and used for debugging and development. If
__str__ is not defined, Python uses __repr__ as a fallback.
class ComplexNumber:
def __init__(self, real=0, imag=0):
self.real = real
self.imag = imag
def __str__(self):
.
return f"{self.real} + {self.imag}j"
m
def __repr__(self):
ru
return f"ComplexNumber({self.real}, {self.imag})"
Fo
if isinstance(other, ComplexNumber):
return ComplexNumber(self.real + other.real, self.imag +
other.imag)
ST
else:
raise TypeError("Can only add another ComplexNumber")
R
c1 = ComplexNumber(2, 3)
c2 = ComplexNumber(1, 1)
ht
In this example, we create a ComplexNumber class that represents a complex number, and
yr
define the __str__, __repr__, and __add__ methods to provide string representation and
addition functionality.
op
Let's consider a real-world example of a Library Management System. We'll define a Book
class to manage book entities. We will also use special methods to define some behavior for
our Book class:
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
self.is_issued = False # Whether the book is issued to a
def __str__(self):
return f"'{self.title}' by {self.author}"
def __len__(self):
return self.pages
.
else:
m
raise TypeError("Can only add another Book instance")
ru
def issue(self):
if not self.is_issued:
self.is_issued = True
Fo
else:
raise ValueError(f"'{self.title}' is already issued to a
borrower")
ST
def return_book(self):
if self.is_issued:
R
self.is_issued = False
else:
raise ValueError(f"'{self.title}' is not issued")
ht
the book
print(book1) # '1984' by George Orwell
op
# The __len__ method provides the length (number of pages) of the book
print(len(book1)) # 328
C
# The __add__ method allows adding two book objects which returns the
total pages
print(book1 + book2) # 609
# Issue a book
book1.issue()
# Try to issue it again (will raise an error because the book is already
issued)
In this system, each Book object represents a book in a library. The issue and return_book
methods represent a book being issued to a borrower or returned to the library, respectively.
We also define the __str__, __len__, and __add__ special methods to allow for intuitive
.
m
interaction with our Book objects.
ru
8.6 Working with Class and Static Methods
Fo
In Python, methods inside a class are by default instance methods, meaning that they are
tied to the instance of the class and can access instance-specific attributes and methods.
However, there are two additional types of methods: class methods and static methods.
These methods are not bound to an instance, but instead to the class or none at all.
ST
8.6.1 Understanding @classmethod
The @classmethod decorator can be applied to a method within a class to make it a class
R
method. A class method is bound to the class and not the instance. This means it can't
access or modify instance-specific attributes, but it can access or modify class attributes.
ht
A class method's first parameter is not self (the instance), but cls (the class).
ig
class MyClass:
yr
class_attribute = 10
@classmethod
op
MyClass.modify_class_attribute(20)
print(MyClass.class_attribute) # Output: 20
In this example, modify_class_attribute is a class method that can modify the class
attribute class_attribute.
class MyClass:
@staticmethod
def my_utility_method(a, b):
return a * b
result = MyClass.my_utility_method(5, 6)
print(result) # Output: 30
.
m
In this example, my_utility_method is a static method that doesn't access any instance or
class data.
ru
8.6.3 Differences and use-cases for class and static methods
Fo
● Use instance methods for most general use-cases, as they can access and modify
instance data.
ST
● Use class methods when you want to provide a method that's tied to the class, but
not any particular instance. This is often useful for factory methods, which create an
instance of a class, because the method can't be tied to any particular instance if it's
being used to create one.
R
● Use static methods as utility functions that don't depend on any class or instance
data.
ht
These three types of methods provide a great deal of flexibility and control over how you
design your classes in Python. By understanding when to use each, you can write cleaner,
ig
class, and also introduce a Library class, which will keep track of the books it contains. This
Library class will make use of instance methods, class methods, and static methods.
C
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
self.is_issued = False
def __str__(self):
return f"'{self.title}' by {self.author}"
def issue(self):
.
if not self.is_issued:
m
self.is_issued = True
else:
ru
raise ValueError(f"'{self.title}' is already issued to a
borrower")
Fo
def return_book(self):
if self.is_issued:
self.is_issued = False
ST
else:
raise ValueError(f"'{self.title}' is not issued")
R
class Library:
def __init__(self):
ht
self.books = []
if isinstance(book, Book):
self.books.append(book)
yr
else:
raise TypeError("Can only add a Book instance")
op
book.issue()
else:
raise ValueError("Book not available for issuing")
@classmethod
def with_books(cls, books):
library = cls()
for book in books:
library.add_book(book)
return library
def total_pages_in_library(self):
return sum(len(book) for book in self.books)
.
book2 = Book("To Kill a Mockingbird", "Harper Lee", 281)
m
# Create a library with books
ru
library = Library.with_books([book1, book2])
# Issue a book
Fo
library.issue_book(book1)
This example builds a simple Library Management System where we can add books to the
library, issue books, and also calculate the total number of pages in the library. It uses
ig
instance methods, class methods, and static methods in a way that makes sense for their
purpose and functionality. The class method with_books is used as a factory method to
create a new library with a list of books. The static method is_book_object is used as a
yr
type.
In the form isinstance(object, classinfo), the function returns True if the object
argument is an instance of the classinfo argument, or of a (direct, indirect, or virtual)
subclass thereof. If object is not an object of the given type, the function returns False.
If classinfo is a tuple of type objects (or recursively, other such tuples), return True if
object is an instance of any of the types. If classinfo is not a type or tuple of types and such
tuples, a TypeError exception is raised.
class Fruit:
pass
class Apple(Fruit):
pass
a = Apple()
.
print(isinstance(a, Fruit)) # Returns: True because Apple is a subclass
m
of Fruit
print(isinstance(a, str)) # Returns: False
ru
In the context of our Library Management System, we used isinstance() to check if an
Fo
object was an instance of the Book class before adding it to the library or issuing it. This is a
way of using Python's dynamic typing to our advantage, while still making sure that we're
working with the kind of objects we expect.
ST
8.7 Python's Built-In OOP Features
Python provides several built-in functions to work with objects and classes. These functions
R
make it easier to inspect and manipulate objects in your program. In this section, we'll cover
the following functions:
ht
● isinstance
● issubclass
ig
● hasattr
● getattr
yr
● setattr
● delattr
op
isinstance(object, classinfo)
Here, object is the object that you want to check, and classinfo is a class, a type, or a tuple
of classes and types.
The isinstance function returns True if the object is an instance of the class or one of its
subclasses, and False otherwise.
class Fruit:
pass
class Apple(Fruit):
pass
apple = Apple()
.
print(isinstance(apple, Fruit)) # True
m
print(isinstance(apple, object)) # True
ru
As you can see, isinstance can help us confirm the class of an object, including its
inheritance hierarchy.
Fo
8.7.2 The issubclass function
The issubclass function is used to check if a class is a subclass of another class. Its syntax
ST
is as follows:
issubclass(class, classinfo)
R
Here, class is the class that you want to check, and classinfo is a class, a type, or a
tuple of classes and types.
ht
The issubclass function returns True if class is a subclass of classinfo, and False
ig
otherwise.
yr
class Fruit:
pass
C
class Apple(Fruit):
pass
As you can see, issubclass can help us confirm the inheritance relationship between two
classes.
The hasattr function checks if an object has a given attribute, getattr gets the value of a
given attribute, setattr sets the value of a given attribute, and delattr deletes a given
attribute.
.
class Fruit:
m
def __init__(self, color):
self.color = color
ru
apple = Fruit('red')
Fo
# hasattr
print(hasattr(apple, 'color')) # True
print(hasattr(apple, 'taste')) # False
ST
# getattr
print(getattr(apple, 'color')) # 'red'
# print(getattr(apple, 'taste')) # Raises AttributeError
R
# setattr
setattr(apple, 'color', 'green')
ht
print(apple.color) # 'green'
ig
# delattr
delattr(apple, 'taste')
op
class Person:
def __init__(self, name, age):
self.name = name
class Teacher(Person):
def __init__(self, name, age, subject):
super().__init__(name, age)
self.subject = subject
class Student(Person):
def __init__(self, name, age, grade):
super().__init__(name, age)
self.grade = grade
.
m
def person_details(person):
print(f"Name: {person.name}")
ru
print(f"Age: {person.age}")
Fo
if hasattr(person, 'subject'):
print(f"Subject: {getattr(person, 'subject')}")
elif hasattr(person, 'grade'):
ST
print(f"Grade: {getattr(person, 'grade')}")
# Create instances
teacher = Teacher("John Doe", 40, "Mathematics")
student = Student("Jane Doe", 15, "10th")
ig
# Display details
person_details(teacher)
print("----------------")
person_details(student)
In this script:
.
m
ru
Fo
ST
R
ht
ig
yr
op
C