0% found this document useful (0 votes)
0 views

IHub Python BootCamp

Python, developed in 1990, is a high-level, interpreted programming language known for its readability and versatility across various applications. It features a simple syntax that makes it accessible for beginners and supports multiple data types including numbers, strings, and booleans. The document outlines key concepts such as data types, variables, and basic operations, providing a foundational understanding for new programmers.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
0 views

IHub Python BootCamp

Python, developed in 1990, is a high-level, interpreted programming language known for its readability and versatility across various applications. It features a simple syntax that makes it accessible for beginners and supports multiple data types including numbers, strings, and booleans. The document outlines key concepts such as data types, variables, and basic operations, providing a foundational understanding for new programmers.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 211

Subi Subi

Python3 For
Beginners.

Subi Subi
Subi Subi
What is Python?

Developed in 1990, Python is one of the most


popular general-purpose programming
languages in modern times.The term
“general-purpose” simply means that Python can
be used for a variety of applications and does
not focus on any one aspect of programming.

Subi Subi
Subi Subi

A High-Level Language
Python falls under the category of high-level, interpreted languages. A
high-level language is one which cannot be understood directly by our
machine. There is a certain degree of abstraction in its syntax. Machines are
generally designed to read machine code, but high-level syntax cannot be
directly converted to machine code.

As a result, it must first be converted to bytecode which is then converted to


machine code before the program can be executed.

Python is an interpreted language because, during execution, each line is


interpreted to the machine language on-the-go.

However, if we take the example of C, the code needs to be compiled into an


executable first, and then it can be executed. In Python, we can skip this
compilation step (Python does it for us behind the scenes) and directly run the
code.

Subi Subi
Subi Subi
Readability
One of the biggest reasons for Python’s rapid growth is
the simplicity of its syntax. The language reads almost
like plain English, making it easy to write complex
programs.

Since it doesn’t have much of a learning curve, Python is


a very good entry point into the world of programming
for beginners.

Subi Subi
Subi Subi
Applications

Apart from the ease of learning, Python is a very efficient


language which is used in almost every sphere of modern
computing.

This makes a strong case for learning Python, even for


non-programmers.

Some of Python’s main applications are highlighted


below:

Subi Subi
Subi Subi

Subi Subi
Subi Subi
Table of Contents
● Data types & Variables
○ Intro
○ Numbers
○ Bools
○ Strings
○ “None”
○ String Slicing & Formatting
○ Grouping Values
○ Operators
■ Arithmetic
■ Comparison
■ Assignment
■ LoiHubal
■ Bitwise
○ String Operations
○ Grouping Values
Subi Subi
Subi Subi
Table of Contents
● Conditional Statements
○ Intro
○ The If statement
○ If-Else
○ If Elif Else
● Functions
○ Intro
○ Creating Functions
○ Function Scope
○ Built-In Str Function
○ Type Conversions
○ Taking User Inputs
○ Lambdas
○ Function As Arguments
○ Recursion
Subi Subi
Subi Subi
Table of Contents
● Loops
○ Intro
○ For… loop
○ Nested For… loop
○ Break , Continue Keywords
○ While… loop
○ Try… Except (Error Handling)
● Data Structures
○ Intro
○ Lists
○ Lists Operations
○ Tuples
○ Dicts
○ Dicts Operations
Subi Subi
Subi Subi
Table of Contents
● Data Structures
○ Sets
○ Set Theory Operations
○ Data Structure Conversions
● Libraries
○ Intro To Python Standard Library
○ Popular Modules
○ PyPi
● POOP (Iff Time Permits)

Subi Subi
Subi Subi

Installing & Setting Up


Python IDE in your PC

Subi Subi
Subi Subi

Understanding Syntax &


Writing Our First Code

Subi Subi
Subi Subi

The print Statement


Whenever we learn a new language, it is an age-old tradition to start by displaying
the text “Hello World” on the screen.

Every language has a different syntax for displaying or printing something on the
screen.

Since Python is one of the most readable languages out there, we can print data
on the terminal by simply using the print statement.

Here’s what the statement looks like:

print (data)

Whatever we need to print is encapsulated in the parentheses following the print


keyword. Let’s try printing “Hello World” on the terminal:

print("Hello World")

The text Hello World is bounded by quotation marks because it is a string or a


group of characters.
Subi Subi
Subi Subi
Printing Multiple Pieces of Data
We can even print multiple things in a single print command; we just have to
separate them using commas.

print(50, 1000, 3.142, "Hello World")

By default, each print statement prints text in a new line. If we want multiple print
statements to print in the same line, we can use the following code:

print("Hello", end="") The value of end is


appended to the
print("World")
output and the next
print("Hello", end=" ") print will continue from
here.
print("World")

Subi Subi
Subi Subi

Comments
Comments are pieces of text used to describe what is happening in the code. They
have no effect on the code whatsoever.

A comment can be written using the # character:

An alternative to these multi-line


print(50) # This line prints 50
comments (line 4 - 8) are
print("Hello World") # This line docstrings. They are encased in
prints Hello World triple quotes, """, and can be used
to replace multi-line comments:
# This is just a comment
hanging out on its own!
""" Docstrings are pretty cool
# For multi-line comments, we
must for writing longer comments

# add the hashtag symbol or notes about the code"""

# each time

Subi Subi
Subi Subi

Data Types and


Variables

Subi Subi
Subi Subi
Python’s Data Types

The data type of an item defines the type and range of values that item can
have.

The concept of data types can be found in the real world. There are numbers,
alphabets, characters, etc., that all have unique properties due to their
classification.

Unlike many other languages, Python does not place a strong emphasis on
defining the data type of an object, which makes coding much simpler. The
language provides three main data types:

● Numbers

● Strings

● Booleans

Subi Subi
Subi Subi
Variables

A variable is simply a name to which a


value can be assigned.

Variables allow us to give meaningful names to


data.

The simplest way to assign a value to a variable


is through the = operator.

A big advantage of variables is that they allow us


to store data so that we can use it later to
perform operations in the code.

Variables are mutable. Hence, the value of a


variable can always be updated or replaced.

Subi Subi
Subi Subi

Naming Convention
There are certain rules we have to follow when picking the name for a variable:

● The name can start with an upper or lower case alphabet.


For example, you can define your income variable as Income or income,
both are valid.

● All the names are case sensitive.


For example, Income and income are two different variables and not one.

● A number can appear in the name, but not at the beginning.


For example, 12income is not a valid name but income12 or in12come are
valid.

Subi Subi
Subi Subi

Naming Convention
● The _ character can appear anywhere in the name.
For example, _income or income_ are valid names.

● Spaces are not allowed. Instead, we must use snake_case to make


variable names readable.
For example, monthly_income is a valid name.

● The name of the variable should be something meaningful that


describes the value it holds, instead of being random characters.

For example, inc or even income would not give any useful information
but names like weekly_income, monthly_income, or annual_income
explain the purpose of our defined variable

Subi Subi
Subi Subi
Numbers

Python is one of the most powerful


languages when it comes to
manipulating numerical data.

It is equipped with support for


several types of numbers, along
with utilities for performing
computations on them.

There are three main types of


numbers in Python:

Subi Subi
Subi Subi

Integers
The integer data type is comprised of all the positive and
negative whole numbers.

The amount of memory an integer occupies depends on its


value. For example, 0 will take up 24 bytes whereas 1 would
occupy 28 bytes. Note: In Python, all negative
numbers start with the - symbol.

Here are some examples of integers:

print(10) # A positive integer


print(-3000) # A negative integer

num = 123456789 # Assigning an integer to a variable


print(num)
num = -16000 # Assigning a new integer
print(num)
Subi Subi
Subi Subi

Floating Point Numbers


Floating-point numbers, or floats, refer to positive
and negative decimal numbers.

Python allows us to create decimals up to a very


high decimal place.

This ensures accurate computations for precise


values.

A float occupies 24 bytes of memory.

Below, we can find some examples of floats:

print(1.00000000005) # A positive float


print(-85.6701) # A negative float

In Python, 5 is considered to be an
flt_pt = 1.23456789
integer while 5.0 is a float.
print(flt_pt)

Subi Subi
Subi Subi

Complex Numbers
Python also supports complex numbers, or numbers made up print(complex(10, 20)) #
of a real and an imaginary part. Represents the complex

Just like the print() statement is used to print values, complex() number (10 + 20j)
is used to create complex numbers. print(complex(2.5, -18.2)) #
Represents the complex
It requires two values. The first one will be the real part of the
number (2.5 - 18.2j)
complex number, while the second value will be the imaginary
part.Here’s the template for making a complex number:
complex_1 = complex(0, 2)
complex(real, imaginary)
complex_2 = complex(2, 0)
Let’s see a few examples: print(complex_1)
print(complex_2)
Note: In normal mathematics, the imaginary part of a complex
number is denoted by i. However, in the code above, it is
denoted by j. This is because Python follows the electrical A complex number
engineering convention which uses j instead of i. Don’t let that usually takes up 32
confuse you. bytes of memory.

Subi Subi
Subi Subi

Booleans

The Boolean (also known as bool) data type allows us to choose between two
values: true and false.

In Python, we can simply use True or False to represent a bool:

print(True)
Note: The first letter
of a bool needs to
f_bool = False be capitalized in
print(f_bool) Python.

A Boolean is used to determine whether the loiHub of an expression or a


comparison is correct. It plays a huge role in data comparisons.

Subi Subi
Subi Subi
Strings print("Harry Potter!") # Double
A group of characters such as this is an example of
the string data type. quotation marks

A string is a collection of characters


got = 'Game of Thrones...' # Single
closed within single, double or triple
quotation marks. quotation marks
print(got)
A string can also contain a single character or be
print("$") # Single character
entirely empty.

From the examples beside we can empty = ""


see: print(empty) # Just prints an empty

● A blank space inside the line


string quotation marks is
also considered to be a multiple_lines = '''Triple quotes allows
character. multi-line string.'''
● To add a multi-line string we
print(multiple_lines)
can use triple quotes.

Subi Subi
Subi Subi
The Length of a String

The length of a string can be found using the len() built-in function. This length
indicates the number of characters in the string:

random_string = "I am Batman" # 11 characters


print(len(random_string))

Indexing

In a string, every character is given a numerical index based on its position.

A string in Python is indexed from 0 to n-1 where n is its length. This means
that the index of the first character in a string is 0.

Subi Subi
Subi Subi

Accessing Characters
Each character in a string can be accessed using its index. The
index must be closed within square brackets, [], and appended
to the string. If we try to execute

batman = "Bruce Wayne" the code on line

first = batman[0] # Accessing the first character 12, we would get an

print(first) error because the


maximum index is

space = batman[5] # Accessing the empty space in the string len(batman) - 1. A

print(space) higher value is not


within the bounds

last = batman[len(batman) - 1] of the string. Since

print(last) len(batman) is

# The following will produce an error since the larger than

index is out of bounds len(batman) - 1, it

# err = batman[len(batman)] will produce an


error.
Subi Subi
Subi Subi
Reverse Indexing

We can also change our indexing convention by using negative


indices.

Negative indices start from the opposite end of the string.


Hence, the -1 index corresponds to the last character:

batman = "Bruce Wayne"


print(batman[-1]) # Corresponds to batman[10]
print(batman[-5]) # Corresponds to batman[6]

Subi Subi
Subi Subi

String Immutability
Once we assign a value to a string, we can’t update it later. How about verifying
it with an executable below?

string = "Immutability"
string[0] = 'O' # Will give error

The above code gives TypeError because Python doesn’t support item
assignment in case of strings.

Remember, assigning a new value to string variable doesn’t mean that


you’ve changed the value. Let’s verify it with the id() method below.

str1 = "hello"
print(id(str1)) Notice, when we assign a new
str1 = "bye" value to str1 (at line 4) its identity
changes not the value.
print(id(str1))

Subi Subi
Subi Subi
ASCII Versus Unicode

In Python 3.x, all strings are unicode. But, older versions


of Python (Python 2.x) support only ASCII characters. To
use unicode in Python 2.x, preceding the string with a u is
must. For example:

string = u"This is unicode"

Subi Subi
Subi Subi

The None Keyword


Introduction to NoneType

Python offers another data type called NoneType. It only has a single value,
None. We can assign None to any variable, but we can not create other
NoneType variables.

Let’s look at an example below. Important Points

val = None ● None is not a default value for


print(val) # prints "None" and returns None the variable that has not yet been
assigned a value.
print (type(val))
● None is not the same as False.
● None is not an empty string.
● None is not 0.

Subi Subi
Subi Subi

String Slicing
Slicing is the process of obtaining
a portion (substring) of a string by
using its indices.

Given a string, we can use the following


template to slice it and obtain a substring:

string[start:end]

Let’s look at a few examples: ● start is the index from


where we want the
my_string = "This is MY string!" substring to start.
print(my_string[0:4]) # From the start till ● end is the index where we
before the 4th index want our substring to end.
print(my_string[1:7]) ● The character at the end
index in the string, will not
print(my_string[8:len(my_string)]) # From the
be included in the
8th index till the end
substring obtained through
this method.
Subi Subi
Subi Subi

Slicing with a Step


Python 3 also allows us to slice a string by defining a step through which we can
skip characters in the string. The default step is 1, so we iterate through the
string one character at a time.

The step is defined after the end index:

string[start:end:step]

Let’s see how this works:

my_string = "This is MY string!"


print(my_string[0:7]) # A step of 1
print(my_string[0:7:2]) # A step of 2
print(my_string[0:7:5]) # A step of 5

Subi Subi
Subi Subi

Reverse Slicing
Strings can also be sliced to return a reversed substring. In this
case, we would need to switch the order of the start and end
indices.

A negative step must also be provided:

my_string = "This is MY string!"


print(my_string[13:2:-1]) # Take 1 step back each time
print(my_string[17:0:-2]) # Take 2 steps back. The opposite of what
happens in the slide above

Subi Subi
Subi Subi

Partial Slicing
One thing to note is that specifying the start and end indices is optional.

If start is not provided, the substring will have all the characters until the end
index.

If end is not provided, the substring will begin from the start index and go all
the way to the end.

Let’s see this in action:

my_string = "This is MY string!"


print(my_string[:8]) # All the characters before 'M'
print(my_string[8:]) # All the characters starting from 'M'
print(my_string[:]) # The whole string
print(my_string[::-1]) # The whole string in reverse (step is -1)

That’s pretty much all we need to know about string slicing. Play around with
the strings above to get a better understanding of how slicing works.

Subi Subi
Subi Subi

String Formatting

String formatting means substituting values into a


string. Following are some use cases of string
formatting:
● Inserting strings within a string
● Inserting integers within a string
● Inserting floats within a string

Subi Subi
Subi Subi
Inserting Strings Within a String

string1 = "I like %s" % "Python"


The %s is the format specifier,
print(string1) # 'I like Python'
which tells Python to insert the
text here. Python will insert a
temp = "iHub" string if:
string2 = "I like %s" % temp
● We follow the string with a
print(string2) # 'I like iHub' % and another string.
● We follow the string with a
string3 = "I like %s and %s" % ("Python", temp) % and another string
print(string3) # 'I like Python and iHub' type variable.

Look at line 8. We can also


insert multiple strings by
putting multiple instances of
%s inside our string

Subi Subi
Subi Subi
Inserting Integers Within a String

my_string = "%i + %i = %i" % (1,2,3)


print(my_string) # '1 + 2 = 3'

The %i is the format specifier, which tells Python to insert the


integers here.

Subi Subi
Subi Subi
Inserting Floats Within a String

string1 = "%f" % (1.11)


print(string1) # '1.110000' %f is used to substitute floats
within a string. Note, string1
string2 = "%.2f" % (1.11) includes extra zeroes. How
print(string2) # '1.11' about limiting 1.111.11 to two
decimal places? We can use
%.2f (line 4).
string3 = "%.2f" % (1.117)
print(string3) # '1.12' If we pass a float that’s greater
than two decimal places, then
%.2f will round off the number
(line 7).

Subi Subi
Subi Subi

Operators
Operators are used to perform arithmetic and
loiHubal operations on data. They enable us to
manipulate and interpret data to produce useful
outputs.
The 5 main operator types in
Operators are represented by characters or
Python are:
special keywords.
● arithmetic operators
In general, Python’s operators follow the in-fix or
prefix notations.
● comparison operators
In-fix operators appear between two operands
(values on which the operator acts) and hence, ● assignment operators
are usually known as binary operators:
● loiHubal operators
A prefix operator usually works on one operand
and appears before it. Hence, prefix operators ● bitwise operators
are known as unary operators:

Subi Subi
Subi Subi

Arithmetic Operators
Below, we can find the basic arithmetic operators in order of precedence. The
operator listed higher will be computed first.

These operators allow us to perform arithmetic operations in Python.

Operator Purpose Notation

() Parentheses Encapsulates the


Precedent Operation

** Exponent In-fix

%, *, /, // Modulo, Multiplication, In-fix


Division, Floor Division

+, - Addition, Subtraction In-fix

Subi Subi
Subi Subi

Addition
We can add two numbers using the + operator:

print(10 + 5)

float1 = 13.65
float2 = 3.40
print(float1 + float2)

num = 20
flt = 10.5
print(num + flt)

As we can see in line 9, summing an integer and floating-point number gives us a


floating-point number.

Python automatically converts the integer to a floating-point number. This applies to all
arithmetic operations.

Subi Subi
Subi Subi
Subtraction

We can subtract one number from the other using the - operator:

print(10 - 5)

float1 = -18.678
float2 = 3.55
print(float1 - float2)

num = 20
flt = 10.5
print(num - flt)

Subi Subi
Subi Subi

Multiplication

We can multiply two numbers using the * operator:

print(40 * 10)

float1 = 5.5
float2 = 4.5
print(float1 * float2)

print(10.2 * 3)

Subi Subi
Subi Subi
Division

We can divide one number by another using the / operator:

print(40 / 10)

float1 = 5.5
float2 = 4.5
print(float1 / float2)
print(12.4 / 2)

A division operation always results in a floating-point number.

Subi Subi
Subi Subi
Floor Division

In floor division, the result is floored to the nearest smaller integer. It is also
known as integer division.

For floor division, we must use the // operator:

print(43 // 10)

float1 = 5.5
float2 = 4.5
print(5.5 // 4.5)
print(12.4 // 2)

Unlike normal division, floor division between two integers results in an integer.

Subi Subi
Subi Subi
Modulo
A number’s modulo with another number can be found using
the % operator:

print(10 % 2)

twenty_eight = 28
print(twenty_eight % 10)

print(-28 % 10) # The remainder is positive if the right-hand


operand is positive
print(28 % -10) # The remainder is negative if the right-hand
operand is negative
print(34.4 % 2.5) # The remainder can be a float

Subi Subi
Subi Subi
Precedence
An arithmetic expression containing different operators will be computed on
the basis of operator precedence.

Whenever operators have equal precedence, the expression is computed from


the left side:

# Different precedence
print(10 - 3 * 2) # Multiplication computed first, followed by subtraction

# Same precedence
print(3 * 20 / 5) # Multiplication computed first, followed by division
print(3 / 20 * 5) # Division computed first, followed by multiplication

Subi Subi
Subi Subi
Parentheses

An expression which is enclosed inside parentheses will be computed first,


regardless of operator precedence:

print((10 - 3) * 2) # Subtraction occurs first


print((18 + 2) / (10 % 8))

Using all the operations above, we can compute

complex mathematical expressions in Python!

Keep in mind that we are never restricted to these operators only, there are
countless more arithmetic utilities at our disposal.

Subi Subi
Subi Subi
Comparison Operators

Comparison operators can be used to compare values in mathematical terms.

Operator Purpose Notation

> Greater Than In-fix

< Less Than In-fix

>= Greater Than or Equal To In-fix

<= Less Than or Equal To In-fix

== Equal To In-fix

!= Not Equal To In-fix

is Equal To (Identity) In-fix

is not Not Equal To (Identity) In-fix

Subi Subi
Subi Subi

Comparisons
The result of a comparison is always a bool.

If the comparison is correct, the value of the bool will be


True. Otherwise, its value will be False.

The == and != operators compare the values of both


operands. However, the identity operators, is and is not,
check whether the two operands are the exact same object.

Let’s look at a few examples:

Subi Subi
Subi Subi
num1 = 5
num2 = 10
num3 = 10
list1 = [6,7,8] As we can see in
list2 = [6,7,8] line 7, num2 is
indeed greater
print(num2 > num1) # 10 is greater than 5 than num1. Hence,
the result is True.
print(num1 > num2) # 5 is not greater than 10
On the other
hand, line 8
print(num2 == num3) # Both have the same value contains an
print(num3 != num1) # Both have different values incorrect
comparison, which
print(3 + 10 == 5 + 5) # Both are not equal results in False.

print(3 <= 2) # 3 is not less than or equal to 2

print(num2 is not num3) # Both have the same object


print(list1 is list2) # Both have the different objects

Subi Subi
Subi Subi
Assignment Operators
This is a category of operators which is used to assign values to a variable. The
= operator is an assignment operator, but not the only one.

Here’s a list of all the assignment operators supported in Python:

Operator Purpose Notation

= Assign In-fix

+= Add and Assign In-fix

-= Subtract and Assign In-fix

*= Multiply and Assign In-fix

/= Divide and Assign In-fix

//= Divide, Floor, and Assign In-fix

Subi Subi
Subi Subi

**= Raise power and Assign In-fix

%= Take Modulo and Assign In-fix

|= OR and Assign In-fix

&= AND and Assign In-fix

^= XOR and Assign In-fix

>>= Right-shift and Assign In-fix

<<= Left-shift and Assign In-fix

Subi Subi
Subi Subi
Assigning Values

Let’s go through a few examples to see how values are assigned to variables.

Variables are mutable, so we can change their values whenever we want!

One thing to note is that when a


year = 2019 first = 20
variable, first, is assigned to
print(year) second = first
another variable, second, its
value is copied into second. first = 35 # Updating 'first'
year = 2020 Hence, if we later change the
print(year) value of first, second will remain print(first, second) # 'second'
unaffected: remains unchanged
year = year + 1 # Using the
existing value to create a new
one
print(year)

Subi Subi
Subi Subi
The Other Operators

Below, we can see some of the assignment operators we talked about in action:

num = 10
print(num)
num += 5
print(num)
num -= 5
print(num)
num *= 2
print(num)
num /= 2
print(num)
num **= 2
print(num)

Subi Subi
Subi Subi
LoiHubal Operators

LoiHubal operators are used to manipulate the loiHub of Boolean expressions.

Operator Purpose Notation

and AND In-fix

or OR In-fix

not NOT Prefix

Subi Subi
Subi Subi
LoiHubal Expressions

LoiHubal expressions are formed using Booleans and loiHubal operators.

Below, we can find some examples:

# OR Expression
my_bool = True or False
print(my_bool)

# AND Expression
my_bool = True and False
print(my_bool)

# NOT expression
my_bool = False
print(not my_bool)
Subi Subi
Subi Subi
Bit Value

All the code we see around us in today’s world is actually


made up of bits. Combinations of 1s and 0s form the
foundation of programming.

In bit terms, the value of True is 1. False corresponds to 0:

print(10 * True)
print(10 * False)

The Python interpreter can automatically convert the


bool to its numerical form when needed.
Subi Subi
Subi Subi
Bitwise Operators
In programming, all data is actually made up of 0s and 1s
known as bits. Bitwise operators allow us to perform
bit-related operations on values.
Examples
Operator Purpose Notation
num1 = 10 # Binary value = 01010
& Bitwise AND In-fix
num2 = 20 # Binary Value = 10100
| Bitwise OR In-fix print(num1 & num2) # 0 -> Binary value = 00000
print(num1 | num2) # 30 -> Binary value = 11110
^ Bitwise XOR In-fix
print(num1 ^ num2) # 30 -> Binary value = 11110
~ Bitwise NOT Prefix print(~num1) # -11 -> Binary value = -(1011)
print(num1 << 3) # 80 -> Binary value = 0101 0000
<< Shift Bits Left In-fix
print(num2 >> 3) # 2 -> Binary value = 0010
>> Shift Bits Right In-fix

Output : 0 30 30 -11 80 2
Subi Subi
Subi Subi
Explanation
In line 4, we perform the bitwise AND. This operation takes a bit from num1 and
the corresponding bit from num2 and performs an AND between them.

In simple terms, AND can be thought of as a multiplication between the two


operands.

Now, let’s visualize this example:

num1 is 01010 in binary and num2 is 10100.

At the first step, the first binary digits of both numbers are taken:

01010 0 & 1 would give 0 (again, think of it as multiplication).


10100

Next, we take the second digits:

01010
These two will once again give us 0.
10100

Doing this for all pairs, we can see that the answer is 0 each time.

Subi Hence, the output is 00000. Subi


Subi Subi

The OR operation in line 5 will work in the same principle except that instead of
multiplication, we will perform addition between the two binary numbers.
0 OR 1 gives us 1. 1 OR 1 also produces 1 (binary numbers do not go beyond 1). However, 0
OR 0 will give us 0 (0 + 0 is still 0).
Bitwise XOR and NOT will work on each bit as well. You can play with the code to get a
better idea.
The bitshift operations (>> and <<) simply move the bits to either the right or the left.
When a binary number is shifted, a 0 also enters at the opposite end to keep the number
of the same size.

Let’s suppose we have a binary number 0110 (6 in Similarly, we can move 0110 twice to the left
decimal). The operation we perform is 0110 >> 2: with the following operation 0110 << 2:

0110 >> 2 0110 << 2


0011 (move one step to the right) 01100 (move one step to the left)
0001 (move one more step to the right) 011000 (move one more step to the left)
Operation complete Operation complete

Note: In Python, leading zeros are truncated. For example, the number 0011 will be the same
as 11. Similarly, the number 0001011 will be the same as 1011.

Subi Subi
Subi Subi
String Operations
Comparison Operators
Strings are compatible with the comparison operators. Each character has a Unicode
value.This allows strings to be compared on the basis of their Unicode values.
When two strings have different lengths, the string which comes first in the dictionary is
said to have the smaller value.
Let’s look at a few examples:
print('a' < 'b') # 'a' has a smaller Unicode value

house = "Gryffindor" Output:


house_copy = "Gryffindor"
True
print(house == house_copy)
True
new_house = "Slytherin"
False
print(house == new_house)
False
print(new_house <= house)
True
print(new_house >= house)

Subi Subi
Subi Subi
Concatenation
The + operator can be used to merge two strings together:
first_half = "Bat"
The * operator allows us to multiply a string,
second_half = "man"
resulting in a repeating pattern:
full_name = first_half + second_half
print("ha" * 3) Output:
print(full_name)
Output: hahaha
Batman
Search
The in keyword can be used to check if a particular substring exists in another string. If the substring
is found, the operation returns true.

Here’s how it works: random_string = "This is a random string" Output:


False
print('of' in random_string) # Check whether 'of' exists in True
randomString
print('random' in random_string) # 'random' exists!

Subi Subi
Subi Subi
Grouping Values
In Python, we can store multiple values together in a single variable.
While there are many ways of doing so, the most popular is the list.It
is very similar to a string since a string is a collection of characters.
A list is also just a collection of values. However, the values can be of
any type. All we have to do is enclose all the elements in square
brackets, [], and separate them with commas.

my_list = [1, 2.5, "A string", True]


print(my_list)
It’s as simple as that! Lists can be indexed and sliced just like strings.
The len command works with them too:

my_list = [1, 2.5, "A string", True]


print(my_list[2])
print(len(my_list))

Subi Subi
Subi Subi
Exercise: Gravitational Force
Gravitational force is the attractive force that exists between two
masses. It can be calculated by using the following formula:

GMm⁄r²

where G is the gravitational constant, M and m are the two masses,


and r is the distance between them.

You must implement this equation in Python to calculate the


gravitational force between Earth and the moon.

All the values have already been given to you. You must write the
formula in Pythonic syntax and store the answer in the grav_force
variable.

G = 6.67 * (10 ** -11)


M = 6.0 * (10 ** 24) # Mass of Earth
m = 7.34 * (10 ** 22) # Mass of the moon
r = 3.84 * (10 ** 8)
Subi Subi
Subi Subi
Solution Review: Gravitational Force
Solution:

G = 6.67 * (10 ** -11)


M = 6.0 * (10 ** 24) # Mass of Earth
m = 7.34 * (10 ** 22) # Mass of the moon
r = 3.84 * (10 ** 8)
grav_force = (G * M * m) / (r ** 2)
print(grav_force)

There’s nothing tricky going on here. The * operator is used to multiply


the different variables and ** is the power operator we need to square r.
We could have also written r * r.

The parentheses in the grav_force formula are only there to make the
code more readable by separating the upper and lower parts of the
fraction. They are optional in this case (parentheses can have an effect
depending on the equation).
Subi Subi
Subi Subi

Conditional
Statements

Subi Subi
Subi Subi
What are Conditional Statements?
A conditional statement is a Boolean expression that, if True, executes a piece
of code.

It allows programs to branch out into different paths based on Boolean


expressions result in True or False outcomes.
In this way, conditional statements control the flow of the code and
allow the computer to think. Hence, they are classified as control
structures.Conditional statements are an integral part of
programming that every coder needs to know.
To handle conditional statements, Python follows a particular
convention:
if condtional statement is True: There are three types of
# execute expression1 conditional statements in
pass Python:
else:
● if
# execute expression2
● if-else
pass
● if-elif-else

Subi Subi
Subi Subi
The if Statement
The simplest conditional statement that we can write is the if statement. It
comprises of two parts:
The condition
The code to be executed

The : in the illustration besides is necessary to specify the beginning of the if


statement’s code to be executed. However, the parentheses, (), around the
condition are optional. The code to be executed is indented at least one tab
to the right.
Indentation
Indentation plays an essential role in Python. Statements with the same level of indentation
belong to the same block of code. The code of an if statement is indented a space further than
the code outside it in order to indicate that this is an inner and inter-related block.
The convention of our indents must also be consistent throughout a block. If we have used two
spaces to make an indent, we must use two spaces for an indent in the same block. Hence,
always keep indentation in mind when writing code.
Indents are important in other aspects of Python, too.

Subi Subi
Subi Subi
The Flow of an if Statement
An if statement runs like this:

if the condition holds True, execute the code to be executed. Otherwise, skip it
and move on.

Let’s write a simple if statement that verifies the value of an integer:

num = 5
if (num == 5): # The condition is true
Output:
print("The number is equal to 5") # The code is executed
if num > 5: # The condtion is false
The number is equal to 5
print("The number is greater than 5") # The code is not executed

Our first condition simply checks whether the value of num is 5. Since this
Boolean expression returns True, the compiler goes ahead and executes the
print statement on line 4.

As we can see, the print command inside the body of the if statement is
indented to the right. If it wasn’t, there would be an error. Python puts a lot of
emphasis on proper indentation.

Subi Subi
Subi Subi
Conditions with LoiHubal Operators
We can use loiHubal operators to create more complex conditions in the if
statement. For example, we may want to satisfy multiple clauses for the
expression to be True.

num = 12
if num % 2 == 0 and num % 3 == 0 and num % 4 == 0:
# Only works when num is a multiple of 2, 3, and 4 Output:
print("The number is a multiple of 2, 3, and 4") The number is a multiple of 2, 3, and 4
if (num % 5 == 0 or num % 6 == 0): The number is a multiple of 5 and/or 6
# Only works when num is either a multiple of 5 or 6
print("The number is a multiple of 5 and/or 6")

In the first if statement, all the conditions have to be fulfilled since we’re using
the and operator.

In the second if statement, the Boolean expression would be true if either or


both of the clauses are satisfied because we are using the or operator.

Subi Subi
Subi Subi
Nested if Statements
A cool feature of conditional statements is that we can nest them. This means
that there could be an if statement inside another!
Hence, we can use nesting to make complex conditions in our program:

num = 63 Output:
if num >= 0 and num <= 100:
The number is in the 60-70
if num >= 50 and num <= 75:
range
if num >= 60 and num <= 70:
print("The number is in the 60-70 range")

Creating and Editing Values


num = 10 Output
if num > 5:
num = 20 # Assigning a new value to num
new_num = num * 5 # Creating a new value called newNum
20
100
# The if condition ends, but the changes made inside it remain
print(num)
print(new_num)
Subi Subi
Subi Subi
The if-else Statement
What if we want to execute a different set of operations in case an if condition
turns out to be False?
That is where the if-else statement comes into the picture.

There’s nothing too tricky going on here. If the condition turns out
to be False, the code after the else: keyword is executed.
Hence, we can now perform two different actions based on the
condition’s value.
The else keyword will be on the same indentation level as the if
keyword. Its body will be indented one tab to the right just like the if
statement.
Here’s the if-else statement in action:

num = 60
if num <= 50:
print("The number is less than or equal to 50")
Output:
else:
The number is greater than 50
print("The number is greater than 50")

Subi Subi
Subi Subi
Benefits of if-else
The example above could also be written with two if conditions:

num = 60
if num <= 50:
print("The number is less than or equal to 50")
if num > 50:
print("The number is greater than 50")

However, for the second if, we have to specify the condition again.
This can be tricky when dealing with complex conditions. The else
statement automatically handles all the situations when the if fails.

Do keep in mind that the else statement cannot exist on its own. It is
merely a counterpart of the if statement. It can still contain its own
nested if or if-else statements. We’ll leave that as an exercise for you
to try on your own.
Subi Subi
Subi Subi
Conditional Expressions
Conditional expressions use the functionality of an if-else statement in a
different way.

The expression returns an output based on the condition we provide. This


output can be stored in a variable.

A conditional expression can be written in the following way:

output_value1 if condition else output_value2

If the if condition is fulfilled, the output would be output_value1. Otherwise, it


would be output_value2.

Let’s refactor the previous if-else statement into a conditional expression:

num = 60
Output:
output = "The number is less than or equal to 50" \
if num <= 50 else "The number is greater than 50" The number is greater than 50
print(output)
Please note that the backslash \ in the above code is only a line continuation character that can
be used to split a single line into multiple lines.
Subi Subi
Subi Subi
The if-elif-else Statement
The if-else statement handles two sides of the same condition: True
and False. This works very well if we’re working with a problem that
only has two outcomes.
However, in programming, it isn’t always a True or False scenario,
and a problem can have multiple outcomes.
This is where the if-elif-else statement shines. It is the most comprehensive
conditional statement because it allows us to create multiple conditions easily.
The elif stands for else if, indicating that if the previous condition fails, try this one.
Let’s write an if-elif-else statement which checks the state of a traffic signal and
generates the appropriate response:
light = "Red"
if light == "Green":
print("Go")
elif light == "Yellow":
Output
print("Caution")
Stop
elif light == "Red":
print("Stop")
else:
print("Incorrect light signal")
Subi Subi
Subi Subi
Multiple elif Statements#
This is the beauty of the if-elif-else statement. We can have as many
elifs as we require, as long as they come between if and else.
Note: An if-elif statement can exist on its own without an else block
at the end. However, an elif cannot exist without an if statement
preceding it (which naturally makes sense).
Let’s write a piece of code that checks whether the value of an integer is in the
range of 0-9 and prints the word in English:
num = 5
elif num == 5:
if num == 0:
print("Five")
print("Zero")
elif num == 6:
elif num == 1:
print("Six") Output:
print("One")
elif num == 7:
elif num == 2: Five
print("Seven")
print("Two")
elif num == 8:
elif num == 3:
print("Eight")
print("Three")
elif num == 9:
elif num == 4:
print("Nine")
print("Four")
Subi Subi
Subi Subi
An important thing to keep in mind is that an if-elif-else or if-elif statement is not the
same as multiple if statements. if statements act independently. If the conditions of
two successive ifs are True, both statements will be executed. On the other hand, in
if-elif-else, when a condition evaluates to True, the rest of the statement’s conditions
are not evaluated.
num = 10 num = 10
if num > 5: if num > 5:
print("The number is greater print("The number is greater than 5")
than 5") elif num % 2 == 0:
if num % 2 == 0: print("The number is even")
print("The number is even") else:
if not num % 2 == 0: print("The number is odd and less than or equal to 5")
print("The number is odd")
Output Output
The number is greater than 5 The number is greater than 5
The number is even

As we can see, in the if tab, all the statements are computed one by one. Hence, we get multiple outputs.
In the if-elif-else tab, since the first condition holds true, all the others are discarded. This proves to be
more efficient in terms of code performance.
Subi Subi
Subi Subi
Exercise: Discounted Price
In this challenge, you must discount a price according to its value.

● If the price is 300 or above, there will be a 30% discount.


● If the price is between 200 and 300 (200 inclusive), there will be a 20%
discount.
● If the price is between 100 and 200 (100 inclusive), there will be a 10%
discount.
● If the price is less than 100, there will be a 5% discount.
● If the price is negative, there will be no discount.

Sample Input
price = 250

Sample Output
price = 200

Subi Subi
Subi Subi
Solution Review: Discounted Price
To handle all the cases, we’ll use an if-elif statement.
Notice that we only need to specify the lower bound
in each condition. This is because, for every
price = 250
condition, the upper bound is already being
checked in the previous condition. if price >= 300:
price *= 0.7 # (1 - 0.3)
The program will only go into the first elif if the price
elif price >= 200:
is lower than 300.
price *= 0.8 # (1 - 0.2)
This sort of smart structuring in a conditional elif price >= 100:
statement can be very useful when dealing with a price *= 0.9 # (1 - 0.1)
large number of complex cases.
elif price < 100 and price >= 0:
The price after a discount would be price * (1 - price *= 0.95 # (1 - 0.05)
discount). print(price)

Subi Subi
Subi Subi

Functions

Subi Subi
Subi Subi
What are Functions?
A function is a reusable set of operations.
That sounds like a pretty straightforward definition. But what does it exactly mean?
Take the print() and len() statements for instance. Both always perform predefined tasks.
Hence, they are examples of functions!

Why Use Functions?


Think of a function as a box which performs a task. We give it an input and it returns an output.
We don’t need to write the set of instructions again for a different input, we could just call the function
again.
Functions are useful because they make the code concise and simple. The primary benefits of using
functions are:
● Reusability: A function can be used over and over again. You do not have to write redundant code.
For example, a sum() function could compute the sum of all the integers we provide it. We won’t
have to write the summing operation ourselves each time.
● Simplicity: Functions are easy to use and make the code readable. We only need to know the inputs
and the purpose of the function without focusing on the inner workings. This abstraction allows us
to focus more on gaining the output instead of figuring out how it was computed.
An input isn’t even necessary. A function could perform its own computations to complete a task.
Subi Subi
Subi Subi

num1 = 10 num1 = 250 num1 = 100


num2 = 40 num2 = 120 num2 = 100
if num1 < num2: if num1 < num2: if num1 < num2:
minimum = num1 minimum = num1 minimum = num1
else: else: else:
minimum = num2 minimum = num2 minimum = num2
print(minimum) print(minimum) print(minimum)

Subi Subi
Subi Subi
For every new pair of integers, we need to write the if-else statement again.

All this could become much simpler if we had a function to perform the steps
necessary for calculating the minimum.

The good news is that Python already has the min() function:

minimum = min(10, 40)


print(minimum)
minimum = min(10, 100, 1, 1000) # It even works with multiple arguments
print(minimum)
minimum = min("Superman", "Batman") # And with different data types
print(minimum)

Subi Subi
Subi Subi
Types of Functions in Python
Functions are perhaps the most commonly used
feature of Python. There are two basic types of
functions in Python:

○ Built-in functions
○ User-defined functions

len(), min(), and print() are examples of built-in


functions.

The coolest feature, however, is that the language


allows us to create our own functions that perform the
tasks we require.

Subi Subi
Subi Subi
Function Creation
Components of a Function

How do we actually make a function? In Python, a function can be defined using


the def keyword in the following format:

The function name is simply the name we’ll use to identify the function.

The parameters of a function are the inputs for that function. We can use these
inputs within the function. Parameters are optional.

The body of the function contains the set of operations that the function will
perform. This is always indented to the right.

Subi Subi
Subi Subi

Implementation
Let’s start by making a plain function that prints four lines of text. It won’t
have any parameters. We’ll name it my_print_function. We can call the
function in our code using its name along with empty parentheses:
def my_print_function(): # No parameters
print("This")
print("is")
print("A")
print("function")
# Function ended

# Calling the function in the program multiple times


my_print_function()
my_print_function()

Subi Subi
Subi Subi
Function Parameters

Parameters are a crucial part of the function structure.

They are the means of passing data to the function. This data can be used by
the function to perform a meaningful task.

When creating a function, we must define the number of parameters and their
names. These names are only relevant to the function and won’t affect variable
names elsewhere in the code. Parameters are enclosed in parentheses and
separated by commas.

The actual values/variables passed into the parameters are known as


arguments.

The min() function requires two numbers as inputs and prints the smaller one.

Let’s define our own basic form of the min() function that simply prints the
minimum. We’ll name it minimum():

Subi Subi
Subi Subi

Here, we are passing num1 and num2 to the function. The


def minimum(first, second):
positions of the parameters are important. In the case above,
if (first < second):
the value of num1 will be assigned to first as it was the first
print(first)
parameter. Similarly, the value of num2 assigned to second.
else:
print(second) If we call a function with lesser or more arguments than
originally required, Python will throw an error.

A parameter can be any sort of data object; from a simple


num1 = 10 integer to a huge list.
num2 = 20

minimum(num1, num2)

Subi Subi
Subi Subi
The return Statement
So far, we’ve only defined functions that print something. They don’t return
anything back to us. But if we think back, functions return values all the time.
Just take len() for example. It returns an integer which is the length of the data
structure.

To return something from a function, we must use the return keyword. Keep in
mind that once the return statement is executed, the compiler ends the
function. Any remaining lines of code after the return statement will not be
executed.

Let’s refactor the minimum() method to return the smaller value instead of
printing it. Now, it’ll work just like the built-in min() function with two parameters:

Subi Subi
Subi Subi
def minimum(first, second):
if (first < second):
return first
return second

num1 = 10
num2 = 20
result = minimum(num1, num2) # Storing the value returned by the function
print(result)

We’ve learned how to create a function, set its parameters, provide it


arguments, and return data from it. Python really does make it a simple
process.

It is a good practice to define all our functions first and then begin the main
code. Defining them first ensures that they can be used anywhere in the
program safely.

Subi Subi
Subi Subi
Function Scope
The scope of a function means the extent to which the variables and other data
items made inside the function are accessible in code.

In Python, the function scope is the function’s body.

Whenever a function runs, the program moves into the function scope. It moves
back to the outer scope once the function has ended.

Data Lifecycle
In Python, data created inside the function cannot be used from the outside
unless it is being returned from the function.

Variables in a function are isolated from the rest of the program. When the
function ends, they are released from memory and cannot be recovered.

The following code will never work:

Subi Subi
Subi Subi
def func():
name = "Stark"
func()
print(name) # Accessing 'name' outside the function

As we can see, the name variable doesn’t exist in the outer scope, and Python
lets us know.

Similarly, the function cannot access data outside its scope unless the data
has been passed in as an argument.

Subi Subi
Subi Subi

As we can see, the name variable doesn’t exist in the outer scope, and Python
lets us know.

Similarly, the function cannot access data outside its scope unless the data
has been passed in as an argument.

name = "Ned"
def func():
name = "Stark"
func()
print(name) # The value of 'name' remains unchanged.

Subi Subi
Subi Subi
Altering Data
When mutable data is passed to a function, the function can modify or alter it.
These modifications will stay in effect outside the function scope as well. An
example of mutable data is a list.

In the case of immutable data, the function can modify it, but the data will
remain unchanged outside the function’s scope. Examples of immutable data
are numbers, strings, etc.

Let’s try to change the value of an integer inside a function:

num = 20
def multiply_by_10(n):
n *= 10
num = n # Changing the value inside the function
print("Value of num inside function:", num)
return n
multiply_by_10(num)
print("Value of num outside function:", num) # The original value remains unchanged

Subi Subi
Subi So, it’s confirmed that immutable objects are unaffected by the working of a Subi
function. If we really need to update immutable variables through a function, we
can simply assign the returning value from the function to the variable.

Now, we’ll try updating a mutable object through a function:

num_list = [10, 20, 30, 40]


print(num_list)
def multiply_by_10(my_list):
my_list[0] *= 10
my_list[1] *= 10
my_list[2] *= 10
my_list[3] *= 10
multiply_by_10(num_list)
print(num_list) # The contents of the list have been changed

We passed num_list to our function as the my_list parameter. Now, any changes
made to my_list will reflect in num_list outside the function. This would not
happen in the case of an immutable variable.

By this point, we have a better understanding of the scope of a function.


Subi Subi
Subi Subi
Built-In String Functions
Python boasts a huge library of built-in functions.

And trust us when we say that there’s something for almost everyone.

Strings
Functions that are properties of a particular entity are known as
methods. These methods can be accessed using the . operator. The string
data type has several methods associated with it. Let’s look at some of
them.

Search
An alternative for finding a substring using the in keyword is the find()
method. It returns the first index at which a substring occurs in a string. If
no instance of the substring is found, the method returns -1.

-1 is a conventional value that represents a None or failure in case the


Subi output was supposed to be positive. Subi
Subi Subi
Search
For a string called a_string, find() can be used in the following way:

a_string.find(substring, start, end)


substring is what we are searching for.

start is the index from which we start searching in a_string.

end is the index where we stop our search in a_string.

start and end are optional.

random_string = "This is a string"


print(random_string.find("is")) # First instance of 'is' occurs at index 2
Output:
print(random_string.find("is", 9, 13)) # No instance of 'is' in this range
2
-1

Subi Subi
Subi Subi
Replace
The replace() method can be used to replace a part of a string
with another string. Here’s the template we must use:

a_string.replace(substring_to_be_replaced, new_string)

The original string is not altered. Instead, a new string with the
replaced substring is returned.
Output:
a_string = "Welcome to iHub!"
new_string = a_string.replace("Welcome to", Welcome to iHub!
"Greetings from")
Greetings from iHub!

print(a_string)
print(new_string)

Subi Subi
Subi Subi
Changing the Letter Case#
In Python, the letter case of a string can be easily
changed using the upper() and lower() methods.

Let’s try them out:

print("UpperCase".upper()) Output:

print("LowerCase".lower()) UPPERCASE
lowercase

Subi Subi
Subi Subi
Joining strings
With join() method you can join multiple strings.

Let’s try it out:

llist = ['a', 'b', 'c']


print('>>'.join(llist)) # joining strings with >>
print('<<'.join(llist)) # joining strings with << Output:
print(', '.join(llist)) # joining strings with comma and space

a>>b>>c
a<<b<<c
a, b, c
Over here, the string.join(llist) returns a single string, with the elements of the
llist separated by string.
Subi Subi
Subi Subi
Formatting
The format() method can be used to format the specified
value(s) and insert them in string’s placeholder(s). Let’s
try it out:
string1 = "Learn Python {version} at
{cname}".format(version = 3, cname = "iHub")
string2 = "Learn Python {0} at {1}".format(3, "iHub")
string3 = "Learn Python {} at {}".format(3, "iHub")
Output:
print(string1) Learn Python 3 at iHub
print(string2) Learn Python 3 at iHub
print(string3)
Learn Python 3 at iHub
The placeholders can be identified using named indexes {cname}, numbered indexes {0}, or even empty
placeholders {}.
Subi Subi
Subi Subi
Type Conversions
int()
To convert data into an integer, we can use the int() utility.

Keep in mind, a string can only be converted to an integer if it is made up of


numbers.

print(int("12") * 10) # String to integer


Output:
print(int(20.5)) # Float to integer 120
print(int(False)) # Bool to integer
20
# print (int("Hello")) # This wouldn't work!
0

Subi Subi
Subi Subi
ord()
This function can be used to convert a character to its Unicode value:

Output:
print(ord('a'))
print(ord('0')) 97
48
float()
The float() function translates data into a floating-point number:

print(float(24)) Output:
print(float('24.5'))
24.0
print(float(True)) 24.5
1.0

Subi Subi
Subi Subi
str()
To convert data into a string, we must use str():
Output
print(str(12) + '.345')
12.345
print(str(False))
print(str(12.345) + ' is a string') False
12.345 is a string

bool()
This function takes in data and gives us the corresponding Boolean value.

Strings are always converted to True, except if the string is empty. Floats and
integers with a value of zero are considered to be False in Boolean terms:

Subi Subi
Subi Subi
Input From the User
The input() function
In Python, input() function is used to take input from user.

The input is automatically converted to string. If you enter a number, it will also
be converted to a string.

name = input("What is your name? ") Output


print("\nHello,", name)
What is your name?
Hello, iHub

Subi Subi
Subi Subi
Lambdas
We have to specify function names while creating them. However, there is a
special class of functions for which we do not need to specify function names.

Definition

- A lambda is an anonymous function that returns some form of data.

Lambdas are defined using the lambda keyword. Since they return data, it is a
good practice to assign them to a variable.

Syntax

The following syntax is used for creating lambdas:

In the structure above, the parameters are optional.

Let’s try creating a few simple lambdas.

Below, we can find a lambda that triples the value of the parameter and returns
this new value:
Subi Subi
Subi Subi
triple = lambda num : num * 3 # Assigning the lambda to a variable
Output
print(triple(10)) # Calling the lambda and giving it a parameter 30

concat_strings = lambda a, b, c: a[0] + b[0] + c[0]


Output
print(concat_strings("World", "Wide", "Web")) WWW

As we can see, lambdas are simpler and more readable than normal
functions. But this simplicity comes with a limitation.

A lambda cannot have a multi-line expression. This means that our


expression needs to be something that can be written in a single line.

Hence, lambdas are perfect for short, single-line functions.

We can also use conditional statements within lambdas:


Subi Subi
Subi Subi

my_func = lambda num: "High" if num > 50 else "Low"


Output
High
print(my_func(60))
When using conditional statements in lambdas, the if-else pair is necessary. Both cases need to
be covered, otherwise, the lambda will throw an error:

my_func = lambda num: "High" if num > 50 ERROR!!!!

The Purpose of Lambdas


So, what is the point of having lambdas around? We’re still assigning
them to variables, so they do have names.

They can be written in-line, but that isn’t a huge advantage.

Well, lambdas are really useful when a function requires another


function as its argument.
Subi Subi
Subi Subi
Functions as Arguments
In Python, one function can become an
argument for another function. This is
useful in many cases.
Let’s make a calculator function that
requires the add, subtract, multiply, or
divide function along with two numbers
as arguments.
For this, we’ll have to define the four
arithmetic functions as well.
Subi Subi
Subi Subi
Using Simple Functions
def add(n1, n2):
return n1 + n2 Output
def subtract(n1, n2):
return n1 - n2 200
def multiply(n1, n2): 30
return n1 * n2
def divide(n1, n2):
return n1 / n2
def calculator(operation, n1, n2):
return operation(n1, n2) # Using the 'operation' argument as a function
result = calculator(multiply, 10, 20)
print(result)
print(calculator(add, 10, 20))
Python automatically understands that the multiply argument in line 21 is a function, and so,
everything works perfectly.
Subi Subi
Subi Subi
Using Lambdas
For the calculator method, we needed to write four extra functions that could
be used as the argument. This can be quite a hassle.

Why don’t we just pass a lambda as the argument? The four operations are
pretty simple, so they can be written as lambdas.

Let’s try it:

def calculator(operation, n1, n2):


return operation(n1, n2) # Using the 'operation' argument as a function
# 10 and 20 are the arguments.
result = calculator(lambda n1, n2: n1 * n2, 10, 20)
Output
# The lambda multiplies them.
print(result) 200
print(calculator(lambda n1, n2: n1 + n2, 10, 20)) 30

Subi Subi
Subi Subi
More Examples
The built-in map() function creates a map object using an existing list and a
function as its parameters. This object can be converted to a list using the list()
function.

The template for map() is as follows:

map(function, list)
The function will be applied, or mapped, to all the elements of the list.

Below, we’ll use map() to double the values of an existing list:


num_list = [0, 1, 2, 3, 4, 5]
Output
double_list = map(lambda n: n * 2, num_list)
print(list(double_list)) [0, 2, 4, 6, 8, 10]

This creates a new list. The original list remains unchanged.

Subi Subi
Subi Subi
We could have created a function that doubles a number and used it as the
argument in map(), but the lambda made things simpler.

Another similar example is the filter() function. It requires a function and a list.

filter() filters elements from a list if the elements satisfy the condition that is
specified in the argument function.

Let’s write a filter() function that filters all the elements which are greater than
10:

numList = [30, 2, -15, 17, 9, 100]


Output
greater_than_10 = list(filter(lambda n: n > 10, numList)) [30, 17, 100]
print(greater_than_10)
The function returns a filter object which can be converted to a list using list().

just like map(), filter() returns a new object without changing the original list.

By now, we have a better understanding of how functions can become


arguments and why lambdas are helpful in that situation.

Subi Subi
Subi Subi
Recursion
Recursion is the process in
which a function calls itself
during its execution. Each
recursive call takes the
program one scope deeper
into the function.
The recursive calls stop at the
base case. The base case is a
check used to indicate that
there should be no further
recursion.
Imagine recursive calls as
nested boxes where each box
represents a function call.
Each call makes a new box.
When the base case is
reached, we start moving out
of the boxes one by one:

Subi Subi
Subi Subi
A Simple Example
Let’s write a function which decrements a number recursively until the number
becomes 0: Output

def rec_count(number): 5

print(number) 4
# Base case 3
if number == 0:
2
return 0
rec_count(number - 1) # A recursive call with a different argument 1
print(number) 0
rec_count(5)
1
This is fairly easy to understand. In each call, the value of the number variable is 2
printed. We then check whether the base case has been fulfilled. If not, we make a
recursive call to the function with the current value decremented. 3

One thing to notice is that an outer call cannot move forward until all the inner 4
recursive calls have finished. This is why we get a sequence of 5 to 0 to 5. 5
Subi Subi
Subi Subi
Why Use Recursion?
Recursion is a concept which many find difficult to grasp at
first, but it has its advantages. For starters, it can
significantly reduce the runtime of certain algorithms, which
makes the code more efficient.

Recursion also allows us to easily solve many problems


related to graphs and trees. It is also important in search
algorithms.

However, we need to be careful when using recursion. If we


don’t specify an appropriate base case or update our
arguments as we recurse, the program will reach infinite
recursion and crash. The arguments passed to our recursive
function are updated in each recursive call so that the base
case can eventually be reached.

Subi Subi
Subi Subi
A Complex Example
The Fibonacci sequence is a popular series of numbers in mathematics, where
every number is the sum of the two numbers before it. The first two terms in the
series are 0 and 1:
0 1 1 2 3 5 8 13
Let’s write a function which takes in a number, def fib(n):
n, and returns the nth number in the Fibonacci # The base cases
sequence. It is important to note that for the
if n <= 1: # First number in the sequence
following example, we will be treating all inputs
less than 1 as incorrect and therefore, our input return 0
will start from 1. So, if n == 6, the function will elif n == 2: # Second number in the sequence
return 5:
return 1
First, we handle our base cases. We know that else:
the first two values are always 0 and 1, so that is # Recursive call
where we can stop our recursive calls.
return fib(n - 1) + fib(n - 2)
If n is larger than 2, then it will be the sum of print(fib(6)) Output
the two values before it.

Subi
5
Subi
Subi Subi
Exercise: Repetition and Concatenation
Problem Statement
In this exercise, you must implement the rep_cat function. You are given two
integers, x and y, as arguments. You must convert them into strings. The string
value of x must be repeated 10 times and the string value of y must be repeated
5 times.

At the end, y will be concatenated to x and the resulting string must returned.

Sample Input
x=3
y=4

Sample Output

'333333333344444'

Subi Subi
Subi Subi
Coding Challenge
Take some time to figure out the loiHub behind this problem before jumping to
the implementation. The function skeleton has been created. You only need to
write code in its body.

The pass statement can be erased and replaced with your return statement.

If you get stuck, feel free to check out the solution review in the next lesson.

Good luck!
def rep_cat(x, y):
# Write your code here
pass

Subi Subi
Subi Subi
Solution Review: Repetition and
Concatenation
Explanation
def rep_cat(x, y):
To convert the integers into strings, we
return str(x) * 10 + str(y) * 5
can use the str() method.

The * operator is perfect for


print(rep_cat(3, 4))
replicating the value of a string a
certain number of times.

Two strings can easily be


concatenated using the + operator.

Finally, all of this is returned from the


function using the return statement.
Subi Subi
Subi Subi
Exercise: The Factorial!
Problem Statement
In this challenge, you must implement the factorial() function. It takes an integer
as a parameter and calculates its factorial. Python does have a built-in
factorial function but you’ll be creating your own for practice.

The factorial of a number, n, is its product with all the integers between 0
and n.

The factorial for 0 and 1 is always 1.

Subi Subi
Subi Subi
Sample Input n=5

Sample Output n=120


Coding Challenge
Take some time to understand the loiHub behind this problem before
moving to the implementation. Write an algorithm that handles all cases.

The input will always be an integer, so you don’t need to worry about that.
If the integer is negative, the function always returns -1.

If you feel stuck, feel free to check out the solution review in the next
lesson.

Good luck!
def factorial(n):
pass # Replace with your own code

Subi Subi
Subi Subi
Solution Review: The Factorial!
Explanation
This problem can easily be solved using recursion.
def factorial(n):
The base case is when n is 1 or 0 since it’s the
# Base case
minimum we can go. In either case, we return 1, since
if n == 0 or n == 1:
it is the factorial for both these values.
return 1
if n < 0: Other than that, the only special case is if n is
return -1 negative. That can be handled with a simple if
# Recursive call statement.
return n * factorial(n - 1)
The final and most important step is the recursive
print(factorial(5)) call. Each call returns a product back to the
previous call where the product is multiplied with the
current value of n in that particular call.
Subi Subi
Subi Subi

Loops

Subi Subi
Subi Subi
What are Loops?
Definition
A loop is a control structure that is used to perform a set of
instructions for a specific number of times.

Loops solve the problem of having to write the same set of


instructions over and over again. We can specify the number of
times we want the code to execute.

One of the biggest applications of loops is traversing data


structures, e.g. lists, tuples, sets, etc. In such a case, the loop
iterates over the elements of the data structure while
performing a set of operations each time. Just like conditional
statements, a loop is classified as a control structure because it
directs the flow of a program by making varying decisions in its
iterations. Loops are a crucial part of many popular
programming languages such as C++, Java, and JavaScript.
Subi Subi
Subi Subi
Loops in Python
There are two types of loops
that we can use in Python:

- The for loop


- The while loop
Both differ slightly in terms of
functionality.
Subi Subi
Subi Subi
The for Loop
A for loop uses an iterator to traverse a sequence, e.g. a range of numbers, the
elements of a list, etc. In simple terms, the iterator is a variable that goes
through the list.

The iterator starts from the beginning of the sequence. In each iteration, the
iterator updates to the next value in the sequence.

The loop ends when the iterator reaches the end.

Structure

In a for loop, we need to define three main things:

- The name of the iterator


- The sequence to be traversed
- The set of operations to perform

The loop always begins with the for keyword. The body of the loop is indented to
the right:

The in keyword specifies that the iterator will go through the values in the
sequence/data structure.
Subi Subi
Subi Subi
Looping Through a Range
In Python, the built-in range() function can be used to create a sequence of
integers. This sequence can be iterated over through a loop. A range is
specified in the following format
range(START, END, STEP):
The end value is not included in the list.

If the start index is not specified, its default value is 0.

The step decides the number of steps the iterator jumps ahead after each
iteration. It is optional and if we don’t specify it, the default step is 1, which
means that the iterator will move forward by one step after each iteration.

Let’s take a look at how a for loop iterates through a range of integers::

OUTPUT:
for i in range(1, 11): # A sequence from 1 to 10
if i % 2 == 0: 1 is odd 6 is even
print(i, " is even") 2 is even 7 is odd
else: 3 is odd 8 is even
4 is even 9 is odd
print(i, " is odd") 5 is odd 10 is even
Subi Subi
Subi Subi

As we can see above, rather than individually checking


whether every integer from 1 to 10 is even or odd, we can loop
through the sequence and compute i % 2 == 0 for each
element.

The iterator, i, begins from 1 and becomes every succeeding


value in the sequence.

Let’s see how a loop changes when the step component of a


range is specified:

for i in range(1, 11, 3): # A sequence from 1 to 10 with a step


of 3
Output
print(i)
1 4 7 10

Subi Subi
Subi Subi
Looping Through a List/String
A list or string can be iterated through its indices.

Let’s double each value in a list using a for loop:


float_list = [2.5, 16.42, 10.77, 8.3, 34.21]
print(float_list)
for i in range(0, len(float_list)): # Iterator traverses to the last
index of the list
float_list[i] = float_list[i] * 2
print(float_list)

OUTPUT:
[2.5, 16.42, 10.77, 8.3, 34.21]
[5.0, 32.84, 21.54, 16.6, 68.42]

Subi Subi
Subi Subi

We could also traverse the elements of a list/string directly through


the iterator. In the float_list above, let’s check how many elements are
greater than 10:
float_list = [2.5, 16.42, 10.77, 8.3, 34.21]
count_greater = 0

for num in float_list: # Iterator traverses to the last index of the list
if num > 10:
count_greater += 1 Output
print(count_greater)
3
In this example, num is the iterator. An important thing to keep in mind
is that in the case above, altering num will not alter the actual value in
the list. The iterator makes a copy of the list element.

Subi Subi
Subi Subi
Nested for Loops
Execution of Nested Loops

Python lets us easily create loops within loops.


There’s only one catch: the inner loop will always
complete before the outer loop.

For each iteration of the outer loop, the iterator


in the inner loop will complete its iterations for
the given range, after which the outer loop can
move to the next iteration.
Subi Subi
Subi Subi
Using a Nested for Loop
Let’s take an example. Suppose we want to print two elements whose sum is
equal to a certain number n.

The simplest way would be to compare every element with the rest of the
list. A nested for loop is perfect for this:
n = 50
num_list = [10, 25, 4, 23, 6, 18, 27, 47]
for n1 in num_list: Output
for n2 in num_list: # Now we have two iterators 23 27
if(n1 != n2):
27 23
if(n1 + n2 == n):
print(n1, n2)

In the code above, each element is compared with every other element to
check if n1 + n2 is equal to n. This is the power of nested loops!
Subi Subi
Subi Subi
The break Keyword
Sometimes, we need to exit the loop before it reaches the end. This can happen if we
have found what we were looking for and don’t need to make any more computations in
the loop. A perfect example is the one we have just covered. At a certain point, n1 is 23
and n2 is 27. Our condition of n1 + n2 == n has been fulfilled. But the loops keep running
and comparing all other pairs as well. This is why the pair is printed twice. It would be
nice to just stop it when the pair is found once. That’s what the break keyword is for. It
n = 50 can break the loop whenever we want. Let’s add it to the example above:
num_list = [10, 25, 4, 23, 6, 18, 27, 47]
As we can see, only (23, 27)
found = False # This bool will become true once a pair is found
for n1 in num_list:
is printed this time.
for n2 in num_list: This is because (23, 27) is
Output
if(n1 != n2): the first pair which
if(n1 + n2 == n): 23 satisfies the condition. We
found = True # Set found to True
27 terminate the loop after
break # Break inner loop if a pair is found
that using the found bool.
if found:
Hence, (27, 23) is never
print(n1, n2) # Print the pair
computed.
break # Break outer loop if a pair is found
Subi Subi
Subi Subi
The continue Keyword
When the continue keyword is used, the rest of that particular
iteration is skipped. The loop continues on to the next iteration. We
can say that it doesn’t break the loop, but it skips all the code in the
current iteration and moves to the next one. We don’t need to get
into too much detail, so here’s a simple example:
num_list = list(range(0, 10)) 0
for num in num_list: 1
if num == 3 or num == 6 or num == 8: 2
continue 4
print(num) 5
7
The loop goes into the if block when num is 3, 6, or 8. When this
9
happens, continue is executed and the rest of the iteration, including
the print() statement, is skipped.
Subi Subi
Subi Subi
The pass Keyword
In all practical meaning, the pass statement does
nothing to the code execution. It can be used to
represent an area of code that needs to be written.
Hence, it is simply there to assist you when you haven’t
written a piece of code but still need your entire program
to execute.

num_list = list(range(20)) Output


20
for num in num_list:
pass # You can write code here later on

print(len(num_list))
Subi Subi
Subi Subi
The while Loop
The while loop keeps iterating over a certain set of operations as long as a
certain condition holds True.

It operates using the following loiHub:

While this condition is true, keep the loop running.

Structure
In a for loop, the number of iterations is fixed since we know the size of the
sequence.

On the other hand, a while loop is not always restricted to a fixed range. Its
execution is based solely on the condition associated with it.

Subi Subi
Subi Subi
The while Loop in Action
Here’s a while loop that finds out the maximum power of n before the value
exceeds 1000:
n = 2 # Could be any number
power = 0
val = n
while val < 1000:
power += 1
Output
val *= n
print(power) 9

In each iteration, we update val and check if its value is less than 1000. The
value of power tells us the maximum power n can have before it becomes
greater than or equal to 1000. Think of it as a counter.
Subi Subi
Subi Subi

We can also use while loops with data structures, especially in cases where the
length of data structure changes during iterations.

The following loop computes the sum of the first and the last digits of any
integer:

n = 249
Output
last = n % 10 # Finding the last number is easy
first = n # Set it to `n` initially 11
while first >= 10:
first //= 10 # Keep dividing by 10 until the leftmost digit is reached.
result = first + last
print(result)

Subi Subi
Subi Subi
Cautionary Measures
Compared to for loops, we should be more careful when creating while loops.
This is because a while loop has the potential to never end. This could crash a
program!

Have a look at these simple loops:

while(True): The loops beside will never end because their conditions
print("Hello World") always remain true. Hence, we should always make sure that our
condition has a mutable variable/object that is being updated in the
x=1
loop and will eventually turn the condition false.
while(x > 0):
x += 5

Other Properties
The break, continue, and pass keywords work with while loops.

Like for loops, we can also nest while loops. Furthermore, we can nest the two
types of loops with each other.

Subi Subi
Subi Subi
Iteration vs. Recursion
If we observe closely, there are several similarities
between iteration and recursion. In recursion, a function
performs the same set of operations repeatedly but with
different arguments.

A loop does the same thing except that the value of the
iterator and other variables in the loop’s body change in
each iteration.

Figuring out which approach to use is an intuitive


process. Many problems can be solved through both.

Recursion is useful when we need to divide data into


different chunks. Iteration is useful for traversing data
and also when we don’t want the program’s scope to
Subi
change. Subi
Subi Subi
Exercise: Balanced Brackets
Problem Statement
Given a string containing only square brackets, [], you must check
whether the brackets are balanced or not. The brackets are said to be
balanced if, for every opening bracket, there is a closing bracket.

You will write your code in the check_balance() function, which returns
True if the brackets are balanced and False if they are not.

For an empty string, the function will return True.

For the sake of simplicity, you can assume that the string will not
contain any other characters.

Subi Subi
Subi Subi
Solution Review: Balanced Brackets
The solution relies on the value of the check variable,
which is updated in each iteration. If an opening
bracket is found, check is incremented by 1. In the
def check_balance(brackets): case of a closing bracket, check is decremented by 1.
check = 0
The loiHub is that check should never be negative
for bracket in brackets:
because that would imply that somewhere in the
if bracket == '[':
check += 1
string, there are more closing brackets than opening
elif bracket == ']':
ones. The condition for being unbalanced is satisfied
check -= 1
and we don’t need to check further.
if check < 0: Another case is that after the loop finishes, the value
break of check would be 0 because the brackets match. If
return check == 0 it’s not, the function simply returns False.
bracket_string = '[[[[]]'
print(check_balance(bracket_string))
Subi Subi
Subi Subi
Exercise: A Sum of Zero
Problem Statement

You must implement the check_sum() function which takes in a list and returns
True if the sum of two numbers in the list is zero. If no such pair exists, return
False.

Sample Input
[10, -14, 26, 5, -3, 13, -5]
Sample Output
True

Subi Subi
Subi Subi
Solution Review: A Sum of Zero
def check_sum(num_list):
for first_num in range(len(num_list)):
for second_num in range(first_num + 1, len(num_list)):
if num_list[first_num] + num_list[second_num] == 0:
return True
We can use a nested for loop to
return False obtain all the possible pairs in the
num_list = [10, -14, 26, 5, -3, 13, -5] list.
print(check_sum(num_list)) By using range(), we can make sure
that the inner loop always starts
one index ahead of the outer loop.

This removes the possibility of a


comparison being repeated.
Subi Subi
Subi Subi
Exercise: Fibonacci Series
Fibonacci sequence is a series of numbers where every number is the sum of
the two numbers before it. The first two numbers are 0 and 1:

0 1 1 2 3 5 8 13
You must write the fib() function which takes in a positive integer, n, and returns
the n-th Fibonacci number. However, instead of using recursion, your function
must use any of the loops. (If n is negative or zero, return -1.)

Sample Input
n=7
Sample Output
8

Subi Subi
Subi Subi
def fib(n):
Solution Review: Fibonacci Series
# The first and second values will always be fixed
first = 0
second = 1
if n < 1:
return -1
if n == 1:
return first
if n == 2:
return second
count = 3 # Starting from 3 because we already know the first two values
while count <= n:
fib_n = first + second
first = second
second = fib_n
count += 1 # Increment count in each iteration
return fib_n
n=7
print(fib(n))
Subi Subi
Subi Subi

Data Structures

Subi Subi
Subi Subi
What are Data Structures?
A data structure is a way of storing and organizing data
according to a certain format or structure.

We can find real-life examples of data structures as well.

There are so many lists online about all sorts of topics.


Another example is the use of tables to display schedules. A
novel stores and organizes text in paragraphs.

All these mediums store data and allow us to manipulate or


access it in a certain way.

Data structures are a crucial part of computer


programming. Since we frequently deal with data
manipulation, it is of paramount importance to organize it in
an efficient and meaningful way.

Subi Subi
Subi Subi
Data Structures in Python
Python is equipped with several built-in
data structures to help us efficiently
handle large amounts of data.
The four primary built-in data
structures offered in Python3 are:
- List
- Tuple
- Dictionary
- Set
Subi Subi
Subi Subi
Lists
The list is perhaps the most commonly used data structure in Python. It
allows us to store elements of different data types in one container.

The contents of a list are enclosed by square brackets, [].

Lists are ordered, like strings. Elements are stored linearly at a specific
index.

We can see from the illustration above that a list bears resemblance to a
string.

A string is a collection of characters indexed in a linear fashion. A list is


the same except that it can contain any type of data, even another list!
Subi Subi
Subi Subi
Creating a List
Let’s see how to create a list using square brackets.

jon_snow = ["Jon Snow", "Winterfell", 30]


print(jon_snow)
# Indexing Output
print(jon_snow[0]) ['Jon Snow', 'Winterfell', 30]
# Length
print(len(jon_snow))
Jon Snow
3

The beauty of lists lies in the fact that we are not bound to one type
of data.
Subi Subi
Subi Lists are mutable, which further expands their functionality: Subi

jon_snow = ["Jon Snow", "Winterfell", 30]


Output
print(jon_snow[2])
jon_snow[2] += 3
print(jon_snow[2]) 30
Using range() 33
A range can further be converted into a list by using the list() casting.

Here’s an example of a range being used to create a list of numbers:

num_seq = range(0, 10) # A sequence from 0 to 9


num_list = list(num_seq) # The list() method casts the sequence into a list
print(num_list) Output
num_seq = range(3, 20, 3) # A sequence from 3 to 19 with a step of 3
print(list(num_seq))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[3, 6, 9, 12, 15, 18]
Subi Subi
Subi Subi
List-Ception!
Here’s an example of lists inside another list:

world_cup_winners = [[2006, "Italy"], [2010, "Spain"],


[2014, "Germany"], [2018, "France"]]
print(world_cup_winners)

The nested lists do not even need to be of the same size!

This is not something we can find in Output

many other languages.


[[2006, 'Italy'],
[2010, 'Spain'],
[2014, 'Germany'],
Subi
[2018, 'France']]
Subi
Subi Subi
Sequential Indexing
To access the elements of a list or a string which exists inside another list, we
can use the concept of sequential indexing.

Each level of indexing takes us one step deeper into the list, allowing us to
access any element in a complex list.

All we have to do is specify all the indices in a sequence:

world_cup_winners = [[2006, "Italy"], [2010, "Spain"],


[2014, "Germany"], [2018, "France"]] Output
print(world_cup_winners[1])
print(world_cup_winners[1][1]) # Accessing 'Spain' [2010, 'Spain']
print(world_cup_winners[1][1][0]) # Accessing 'S'
Spain
S

Subi Subi
Subi Subi
Merging Lists
Python makes it really easy to merge lists together. The simplest way is to use
the + operator just like strings:

part_A = [1, 2, 3, 4, 5]
part_B = [6, 7, 8, 9, 10] Output
merged_list = part_A + part_B [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(merged_list)
Alternatively, we could use the extend() property of a list to add the elements of
one list at the end of another:

part_A = [1, 2, 3, 4, 5]
part_B = [6, 7, 8, 9, 10]
Output
part_A.extend(part_B) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(part_A)
Subi Subi
Subi Subi
Common List Operations
Adding Elements
All the elements of a list cannot always be specified beforehand and there’s a
strong possibility that we’ll want to add more elements during runtime.

The append() method can be used to add a new element at the end of a list. The
following template must be followed:

a_list.append(newElement) Note: In the code


Here’s an example: above, we create an
empty list at line 1. This
num_list = [] # Empty list can always be done by
simply using empty
num_list.append(1) Output
square brackets [].
num_list.append(2) [1, 2, 3]
num_list.append(3)
print(num_list)
Subi Subi
Subi Subi
To add an element at a particular index in the list, we can use the
insert() method. We’ll use it in the following format:

aList.insert(index, newElement)

If a value already exists at that index, the whole list from that
value onwards will be shifted one step to the right:

Output
num_list = [1, 2, 3, 5, 6]
num_list.insert(3, 4) # Inserting 4 at the 3rd index. 5 and 6
shifted ahead [1, 2, 3, 4,
print(num_list) 5, 6]
Subi Subi
Subi Subi
Removing Elements
Deleting elements is as easy as adding them. The counterpart of append() is the
pop() operation which removes the last element from the list.

We can store this popped element in a variable:

houses = ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]


last_house = houses.pop() Output
print(last_house)
Slytherin
print(houses)
['Gryffindor', 'Hufflepuff', 'Ravenclaw']

If we need to delete a particular value from a list, we can use the remove()
method by following this template:

aList.remove(element_to_be_deleted)

Subi Subi
Subi houses = ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"] Subi

print(houses)
houses.remove("Ravenclaw")
print(houses)

# For nested lists


populations = [["Winterfell", 10000], ["King's Landing", 50000],
["Iron Islands", 5000]]
print(populations)
populations.remove(["King's Landing", 50000])
Output print(populations)
['Gryffindor', 'Hufflepuff', 'Ravenclaw', 'Slytherin']
['Gryffindor', 'Hufflepuff', 'Slytherin']
[['Winterfell', 10000], ["King's Landing", 50000], ['Iron Islands', 5000]]
[['Winterfell', 10000], ['Iron Islands', 5000]]
Subi Subi
Subi Subi
List Slicing
List slicing is the term used for obtaining a portion of a list given the start and
end indices.
num_list = [1, 2, 3, 4, 5, 6, 7, 8] Output
Slicing a list gives us a sublist:
print(num_list[2:5])
print(num_list[0::2]) [3, 4, 5]
Index Search [1, 3, 5, 7]
With lists its really easy to access a value through its index. However, the
opposite operation is also possible where we can find the index of a given
value.

For this, we’ll use the index() method:

cities = ["London", "Paris", "Los Angeles", "Beirut"]


Output
print(cities.index("Los Angeles")) # It is at the 2nd index 2

Subi Subi
Subi If we just want to verify the existence of an element in a list, we can use the in Subi
operator:
Output
cities = ["London", "Paris", "Los Angeles", "Beirut"]
print("London" in cities) True
print("Moscow" not in cities)
True
List Sort
A list can be sorted in ascending order using the sort() method. Sorting can be
done alphabetically or numerically depending on the content of the list:

num_list = [20, 40, 10, 50.4, 30, 100, 5] Output


num_list.sort()
[5, 10, 20, 30, 40, 50.4, 100]
print(num_list)

Subi Subi
Subi Subi
List Comprehension
List comprehension is a technique that uses a for loop and a condition to
create a new list from an existing one.

The result is always a new list, so it’s a good practice to assign list
comprehension to a new variable.

A list comprehension statement is always enclosed in square brackets, [].

The comprehension consists of three main parts:

● The expression is an operation used to create elements in the new list.

● The for loop will iterate an existing list. The iterator will be used in the
expression.

● New elements will only be added to the new list when the if condition is
fulfilled. This component is optional.

Subi Subi
Subi Subi
Creating a List Comprehension
Let’s create a new list whose values are the doubles of the values of an existing
list.

nums = [10, 20, 30, 40, 50] Output


nums_double = []
for n in nums: [10, 20, 30, 40, 50]
nums_double.append(n * 2)
print(nums) [20, 40, 60, 80, 100]
print(nums_double)

Let’s break down the loop above into the three components of a list
comprehension.

The expression is equivalent to n * 2 since it’s used to create each value in the
new list.

Our for loop is for n in nums, where n is the iterator.

An if condition doesn’t exist in this case.


Subi Subi
Subi So, let’s convert the loop above into a list comprehension: Subi

nums = [10, 20, 30, 40, 50] Output


# List comprehension
nums_double = [n * 2 for n in nums]
[10, 20, 30, 40, 50]
print(nums)
print(nums_double) [20, 40, 60, 80, 100]

Adding a Condition nums = [10, 20, 30, 40, 50]


# List comprehension
Our previous comprehension Output:
did not have a condition. All the nums_double = [n * 2 for n in nums if n % 4 == 0] [10, 20, 30, 40, 50]
values of the nums list were print(nums) [40, 80]
simply doubled and added to print(nums_double)
nums_double.
What if we only wanted our new Now, only 20 and 40 were selected from nums
list to have elements which were since they fulfill the if condition. Hence, the
divisible by 4?
resulting nums_double would contain [40, 80].
We’d simply add an if condition
at the end of our list
comprehension:
Subi Subi
Subi Subi
Using Multiple Lists
List comprehension can also be performed on more than one
list. The number of for loops in the comprehension will
correspond to the number of lists we’re using.

Let’s write a list comprehension which creates tuples out of the


values in two lists when their sum is greater than 100. These
tuples are the elements of the new list. Here’s the code:
list1 = [30, 50, 110, 40, 15, 75] Output:
list2 = [10, 60, 20, 50] [(50, 60),
(110, 10),
sum_list = [(n1, n2) for n1 in list1 for n2 in list2 if n1 + n2 > 100] (110, 60),
print(sum_list) (110, 20),
(110, 50),
(75, 60),
(75, 50)]
We could solve the problem above using a nested for loop as
well, but this approach seems much simpler.
Subi Subi
Subi Subi
Tuples
A tuple is very similar to a list, except for the fact that its contents cannot be
changed. In other words, a tuple is immutable. However, it can contain mutable
elements like a list. These elements can be altered.

The contents of a tuple are enclosed in parentheses, (). They are also ordered,
and hence, follow the linear index notation.

car = ("Ford", "Raptor", 2019, "Red")


print(car)
# Length
print(len(car))
# Indexing Output
print(car[1]) ('Ford', 'Raptor', 2019, 'Red')
Creating a Tuple
# Slicing 4
print(car[2:]) Raptor Tuples can be created similar to
(2019, 'Red') lists. All the indexing and slicing
operations apply to it as well:

Subi Subi
Subi Subi
Merging Tuples
Tuples can be merged using the + operator:
Output
hero1 = ("Batman", "Bruce Wayne") ('Batman', 'Bruce Wayne', 'Wonder
hero2 = ("Wonder Woman", "Diana Prince") Woman', 'Diana Prince')
awesome_team = hero1 + hero2
print(awesome_team)

Nested Tuples

In the previous coding example, instead of merging the two tuples, we could create a new tuple with
these two tuples as its members:

hero1 = ("Batman", "Bruce Wayne") Output


hero2 = ("Wonder Woman", "Diana Prince")
(('Batman', 'Bruce Wayne'),
awesome_team = (hero1, hero2)
('Wonder Woman', 'Diana Prince'))
print(awesome_team)

Subi Subi
Subi Subi
Search
We can check whether an element exists in a tuple by using the in operator as
follows:

cities = ("London", "Paris", "Los Angeles", "Tokyo") Output


print("Moscow" in cities) False

The index() function can give us the index of a particular value:

cities = ("London", "Paris", "Los Angeles", "Tokyo") Output


print(cities.index("Tokyo"))
3
Immutability

Since tuples are immutable, we can’t add or delete elements from them.
Furthermore, it isn’t possible to append another tuple to an existing tuple.

Subi Subi
Subi Subi
Dictionaries
Compared to a list or tuple, a dictionary has a slightly more complex structure.

When we think of a dictionary, what pops up is the


image of a vast book containing words with their
meanings.

In simpler terms, information is stored in pairs of words and


meanings. Python’s dictionary data structure follows the same
structure.

A dictionary stores key-value pairs, where each unique key is an


index which holds the value associated with it.

Dictionaries are unordered because the entries are not stored in


a linear structure.

In Python, we must put the dictionary’s content inside curly


brackets, {}:

A key-value pair is written in the following format:

key:value
Subi Subi
Subi Subi
Creating a Dictionary
Let’s create an empty dictionary and a simple phone_book using the dictionary
data structure:
Output
empty_dict = {} # Empty dictionary
print(empty_dict) {}
{'Batman': 468426, 'Ghostbusters': 44678, 'Cersei':
phone_book = {"Batman": 468426, 237734}
"Cersei": 237734,
"Ghostbusters": 44678}
print(phone_book)

Note: Since the dictionary is an unordered data structure, the order of the output will not
necessarily match the order in which we wrote the entries. Key-value pairs are accessed in a
random or unordered manner.

The dictionary above could also be written in the same line. Dividing it into lines, only increases
readability.
Subi Subi
Subi Subi
The dict() Constructor
As the name suggests, the dict() empty_dict = dict() # Empty dictionary
constructor can be used to print(empty_dict)
construct a dictionary. Think of
the “constructor” as an operation phone_book = dict(Batman=468426,
that gives us a dictionary. If our Cersei=237734, Ghostbusters=44678)
keys are simple strings without
# Keys will automatically be converted to
special characters, we can create
strings
entries in the constructor. In that
case, values will be assigned to print(phone_book)
keys using the = operator. A
popular practice is to create an # Alternative approach
empty dictionary and add entries phone_book = dict([('Batman', 468426),
later.Let’s refactor the empty_dict ('Cersei', 237734),
and phone_book examples to ('Ghostbusters', 44678)])
make them work with dict(): print(phone_book)

Subi Subi
Subi Subi
Accessing Values
The keys and values can have any of the basic data types or structures.

Two keys can have the same value. However, it is crucial that all keys are unique.

We can see from the phone_book example how dictionaries can organize data in a meaningful way. It is
easy to tell a character’s phone number because the pair is stored together.

For many, this is where a dictionary has an edge over a list or a tuple. Since there are no linear indices,
we do not need to keep track of where values are stored.

Instead, we can access a value by enclosing its key in square brackets, []. This is more meaningful than
the integer indices we use for tuples and lists.

Alternatively, we can use the get() method as follows: Output


a_dictionary.get(key) phone_book = {"Batman": 468426,
237734
"Cersei": 237734,
"Ghostbusters" : 44678} 44678
print(phone_book ["Cersei"])
print(phone_book.get ("Ghostbusters" ))
Subi Subi
Subi Subi
Dictionary Operations
Adding/Updating Entries

We can add new entries in a dictionary by simply assigning a value to a key.


Python automatically creates the entry.

If a value already exists at this key, it will be updated:

phone_book = {"Batman": 468426,"Cersei": 237734,"Ghostbusters": 44678}


print(phone_book)
phone_book["Godzilla"] = 46394 # New entry
print(phone_book)
phone_book["Godzilla"] = 9000 # Updating entry
print(phone_book)

Output
{'Cersei': 237734, 'Batman': 468426, 'Ghostbusters': 44678}
{'Cersei': 237734, 'Batman': 468426, 'Godzilla': 46394, 'Ghostbusters': 44678}
{'Cersei': 237734, 'Batman': 468426, 'Godzilla': 9000, 'Ghostbusters': 44678}

Subi Subi
Subi Subi
Removing Entries
To delete an entry, we can use the del keyword:

phone_book = {"Batman": 468426,"Cersei": 237734,"Ghostbusters": 44678}


print(phone_book)
del phone_book["Batman"]
print(phone_book)

Output
{'Ghostbusters': 44678, 'Cersei': 237734, 'Batman': 468426}
{'Ghostbusters': 44678, 'Cersei': 237734}

Subi Subi
Subi Subi

If we want to use the deleted value, the pop() or popitem() methods would work
better:

phone_book = {"Batman": 468426,"Cersei": 237734,"Ghostbusters": 44678}


print(phone_book)
cersei = phone_book.pop("Cersei")
print(phone_book)
print(cersei)
# Removes and returns the last inserted pair, as a tuple
# In Python versions before 3.7, popitem() removes and returns the random item
lastAdded = phone_book.popitem()
print(lastAdded) Output

{'Batman': 468426, 'Cersei': 237734, 'Ghostbusters': 44678}


{'Batman': 468426, 'Ghostbusters': 44678}
237734
('Ghostbusters', 44678)
Subi Subi
Subi Subi
Length of a Dictionary
Similar to lists and tuples, we can calculate the length of a dictionary using len():

phone_book = {"Batman": 468426,"Cersei": 237734,"Ghostbusters": 44678} Output


print(len(phone_book))
3
Checking Key Existence
The in keyword can be used to check if a key exists in a dictionary:
phone_book = {"Batman": 468426,"Cersei": 237734,"Ghostbusters": 44678}
Output
print("Batman" in phone_book)
True
print("Godzilla" in phone_book) False
Copying Contents : To copy the contents of one dictionary to another, we can use the update()
operation:
phone_book = {"Batman": 468426, "Cersei": 237734,"Ghostbusters": 44678}
second_phone_book = {"Catwoman": 67423, "Jaime": 237734, "Godzilla": 37623}
# Add secondphone_book to phone_book
phone_book.update(second_phone_book)
print(phone_book)
Subi Subi
Subi Subi
Dictionary Comprehension
Python also supports dictionary comprehensions, which work very similar to list
comprehensions. We’ll be creating new key-value pairs based on an existing
dictionary.

However, to iterate the dictionary, we’ll use the dict.items() operation which turns a dictionary into a list
of (key, value) tuples. Here’s a simple example where the keys of the original dictionary are squared and
'!' is appended to each string value:

houses = {1: "Gryffindor", 2: "Slytherin", 3: "Hufflepuff", 4: "Ravenclaw"}


new_houses = {n**2: house + "!" for (n, house) in houses.items()}
print(houses)
print(new_houses)

Output
{1: 'Gryffindor', 2: 'Slytherin', 3: 'Hufflepuff', 4: 'Ravenclaw'}
{16: 'Ravenclaw!', 1: 'Gryffindor!', 4: 'Slytherin!', 9: 'Hufflepuff!'}
Subi Subi
Subi Subi
Sets
A set is an unordered collection of data items.
The data is not indexed, so we can’t access elements using indices or get().
This is perhaps the simplest data structure in Python. We can think of it as a bag containing
random items.

Mutable data structures like lists or dictionaries


can’t be added to a set. However, adding a tuple
is perfectly fine.
One might wonder, “Why would I need a set?”
Well, a set is perfect when we simply need to keep
track of the existence of items.
It doesn’t allow duplicates, which means that we
can convert another data structure to a set to
remove any duplicates.

Subi Subi
Subi Subi
Creating a Set
The contents of a set are encapsulated in curly brackets, {}. Like all data
structures, the length of a set can be calculated using len():
Output
random_set = {"iHub", 1408, 3.142,(True, False)}
print(random_set) {1408, (True, False),
print(len(random_set)) # Length of the set 3.142, ‘iHub’}
4
The set() Constructor
The set() constructor is an alternate way of creating sets. The advantage it presents is that it allows us
to make an empty set:
Output
empty_set = set()
print(empty_set)
set()
random_set = set({"iHub", 1408, 3.142, (True, False)})
{1408, (True, False), 3.142, 'iHub'}
print(random_set)

Subi Subi
Subi Subi
Adding Elements
To add a single item, we can use the add() method. To add multiple items, we’d
have to use update(). The input for update() must be another set, list, tuple, or
string. Let’s add elements to an empty set:
Deleting Elements
empty_set = set()
print(empty_set) The discard() or remove() operations can be used to delete a
empty_set.add(1) particular item from a set:

print(empty_set) random_set = set({"iHub", 1408, 3.142, (True, False)})


empty_set.update([2, 3, 4, 5, 6]) print(random_set)
print(empty_set) random_set.discard(1408)
Output
print(random_set)
Output {1408, (True, False),
random_set.remove((True, False))
3.142, 'iHub'}
print(random_set)
set() {(True, False), 3.142,
{1} 'iHub'}
{1, 2, 3, 4, 5, 6} {3.142, 'iHub'}
Subi Subi
Subi Subi
Iterating a Set
The for loop can be used on unordered data structures like sets. However, we
wouldn’t know the order in which the iterator moves meaning elements will be
picked randomly. In the example below, we’ll take the elements of a set and
append them to a list if they are odd:

odd_list = [1, 3, 5, 7]
Output
unordered_set = {9, 10, 11, 12, 13, 14, 15, 16, 17}
{9, 10, 11, 12, 13, 14, 15, 16, 17}
print(unordered_set)
[1, 3, 5, 7, 9, 11, 13, 15, 17]
for num in unordered_set:
if(not num % 2 == 0):
odd_list.append(num)
print(odd_list)

Subi Subi
Subi Subi
Set Theory Operations
Folks familiar with mathematics will know that sets have three main operations,
union, intersection, and difference.
The set data structure in Python supports all three.

Union
A union of two sets is the collection of all unique elements from both sets.

set_A = {1, 2, 3, 4} Output


set_B = {'a', 'b', 'c', 'd'}
{1, 2, 3, 4, 'b', 'd', 'c', 'a'}

print(set_A | set_B) {1, 2, 3, 4, 'b', 'd', 'c', 'a'}


print(set_A.union(set_B)) {1, 2, 3, 4, 'b', 'd', 'c', 'a'}
print(set_B.union(set_A))

Since sets are unordered, the order of contents in the three outputs above
does not matter.

Subi Subi
Subi Subi
Intersection
The intersection of two sets is the collection of unique elements
which are common between them.

set_A = {1, 2, 3, 4}
set_B = {2, 8, 4, 16}
Output

print(set_A & set_B) {2, 4}


print(set_A.intersection(set_B)) {2, 4}
print(set_B.intersection(set_A)) {2, 4}

Subi Subi
Subi Subi
Difference
The difference between two sets is the collection of all unique elements present
in the first set but not in the second.
In Python, the difference between two sets can be found using either the -
operator or the difference() method.
Do keep in mind that the difference operation is not associative, i.e., the
positions of the sets matter.

set_A - set_B returns the elements which are only present in set_A.

set_B - set_A would do the opposite.

set_A = {1, 2, 3, 4}
set_B = {2, 8, 4, 16} Output
print(set_A - set_B)
print(set_A.difference(set_B)) {1, 3} {1, 3} {16, 8} {16, 8}
print(set_B - set_A)
print(set_B.difference(set_A))

Subi Subi
Subi Subi
Data Structure Conversions
The principle of conversion between built-in data
structures in Python is similar to that of Python’s
primitive data types.

Explicit Conversion

The template for explicitly converting from one data


structure to another is as follows:

destination_structure_name(source_structure_object)

destination_structure_name is the name of the data


structure that we want to convert to.

source_structure_object is the object which we want to


convert.
Subi Subi
Subi Subi
Converting to a List
We can convert a tuple, set, or dictionary to a list using the list() constructor. In
the case of a dictionary, only the keys will be converted to a list.

Output
star_wars_tup = ("Anakin", "Darth Vader", 1000)
print(star_wars_tup)
('Anakin', 'Darth Vader', 1000)
star_wars_set = {"Anakin", "Darth Vader", 1000} {1000, 'Anakin', 'Darth Vader'}
print(star_wars_set) {1: 'Anakin', 2: 'Darth Vader', 3:
star_wars_dict = {1: "Anakin", 2: "Darth Vader", 3: 1000} 1000}
print(star_wars_dict) ['Anakin', 'Darth Vader', 1000]
star_wars_list = list(star_wars_tup) # Converting from tuple [1000, 'Anakin', 'Darth Vader']
print(star_wars_list) [1, 2, 3]
star_wars_list = list(star_wars_set) # Converting from set
print(star_wars_list)
star_wars_list = list(star_wars_dict) # Converting from dictionary
print(star_wars_list)

Subi Subi
Subi Subi

We can also use the dict.items() method of a dictionary to convert it into an


iterable of (key, value) tuples. This can further be cast into a list of tuples using
list():

star_wars_dict = {1: "Anakin", 2: "Darth Vader", 3: 1000}


print(star_wars_dict)

star_wars_list = list(star_wars_dict.items())
print(star_wars_list)
Output
{1: 'Anakin', 2: 'Darth Vader', 3: 1000}
[(1, 'Anakin'), (2, 'Darth Vader'), (3, 1000)]

Subi Subi
Subi Subi
Converting to a Tuple
Any data structure can be converted to a tuple using the tuple() constructor. In
the case of a dictionary, only the keys will be converted to a tuple:

Output
star_wars_list = ["Anakin", "Darth Vader", 1000] ['Anakin', 'Darth Vader', 1000]
print(star_wars_list) {1000, 'Anakin', 'Darth Vader'}
star_wars_set = {"Anakin", "Darth Vader", 1000}
{1: 'Anakin', 2: 'Darth Vader', 3:
print(star_wars_set)
1000}
star_wars_dict = {1: "Anakin", 2: "Darth Vader", 3: 1000}
print(star_wars_dict) ('Anakin', 'Darth Vader', 1000)
star_wars_tup = tuple(star_wars_list) # Converting from list (1000, 'Anakin', 'Darth Vader')
print(star_wars_tup)
(1, 2, 3)
star_wars_tup = tuple(star_wars_set) # Converting from set
print(star_wars_tup)
star_wars_tup = tuple(star_wars_dict) # Converting from dictionary
print(star_wars_tup)
Subi Subi
Subi Subi
Converting to a Set
The set() constructor can be used to create a set out of any other data
structure. In the case of a dictionary, only the keys will be converted to a set:

star_wars_list = ["Anakin", "Darth Vader", 1000] Output


print(star_wars_list)
['Anakin', 'Darth Vader', 1000]
star_wars_tup = ("Anakin", "Darth Vader", 1000) ('Anakin', 'Darth Vader', 1000)
print(star_wars_tup) {1: 'Anakin', 2: 'Darth Vader', 3: 1000}
star_wars_dict = {1: "Anakin", 2: "Darth Vader", 3: 1000} {1000, 'Anakin', 'Darth Vader'}
print(star_wars_dict) {1000, 'Anakin', 'Darth Vader'}
{1, 2, 3}
star_wars_set = set(star_wars_list) # Converting from list
print(star_wars_set)
star_wars_set = set(star_wars_tup) # Converting from tuple
print(star_wars_set)
star_wars_set = set(star_wars_dict) # Converting from dictionary
print(star_wars_set)

Subi Subi
Subi Subi
Converting to a Dictionary
The dict() constructor cannot be used in the same way as the others because it requires
key-value pairs instead of just values. Hence, the data must be stored in a format where
pairs exist. For example, a list of tuples where the length of each tuple is 2 can be converted
into a dictionary. Those pairs will then be converted into key-value pairs:

star_wars_list = [[1,"Anakin"], [2,"Darth Vader"], [3, 1000]] Output


[[1, 'Anakin'], [2, 'Darth Vader'], [3, 1000]]
print (star_wars_list)
((1, 'Anakin'), (2, 'Darth Vader'), (3, 1000))
star_wars_tup = ((1, "Anakin"), (2, "Darth Vader"), (3, 1000))
{(3, 1000), (1, 'Anakin'), (2, 'Darth Vader')}
print (star_wars_tup)
{1: 'Anakin', 2: 'Darth Vader', 3: 1000}
star_wars_set = {(1, "Anakin"), (2, "Darth Vader"), (3, 1000)}
{1: 'Anakin', 2: 'Darth Vader', 3: 1000}
print (star_wars_set)
{1: 'Anakin', 2: 'Darth Vader', 3: 1000}
star_wars_dict=dict(star_wars_list)#Converting from list
print(star_wars_dict)
star_wars_dict=dict(star_wars_tup)#Converting from tuple
print(star_wars_dict)
star_wars_dict = dict(star_wars_set) # Converting from set
print(star_wars_dict)
Subi Subi
Subi Subi
Exercise: From List to Tuple
You are given a list called my_list. Using this list, you must create a
tuple called my_tuple. The tuple will contain the list’s first element,
last element, and the length of the list, in that same order.

Sample Input
my_list = [34, 82.6, "Darth Vader", 17, "Hannibal"]

Sample Output
my_tuple = (34, "Hannibal", 5)

There are several ways of solving the problem. Flesh out the loiHub
before moving on to the implementation.

my_list has already been created. You only need to make my_tuple.

my_list = [34, 82.6, 'Darth Vader', 17, 'Hannibal']

Subi Subi
Subi Subi
Solution Review: From List to Tuple
my_list = [34, 82.6, "Darth Vader", 17, "Hannibal"]
my_tuple = (my_list[0], my_list[len(my_list) - 1], len(my_list))
print(my_tuple)

All we have to do is create a tuple with three elements. The first element of the tuple is the
first element of the list, which can be found using my_list[0].

The second element of the tuple is the last element in the list. my_list[len(my_list) - 1] or
simply my_list[-1] will give us this element. We could also have used the pop() method, but
that would alter the list.

We already know how to calculate the length of a data structure, so finding out the third
element of the tuple is pretty easy.

Subi Subi
Subi Subi
Exercise: Kth Maximum Integer in a List
Given a list of integers and a number k, find the kth largest integer in the list. The integer
will be stored in the kth_max variable.

For example, with a list of 7 integers, if k = 2, then kth_max will be equal to the
second-largest integer in the list. If k = 6, kth_max will equal the 6th largest integer.

Take some time to figure out the smartest way to solve this
problem. All the list methods and other data structures are
available for use. The list being used is called test_list.

Write the code in terms of k. You do not need to worry


about its value. Assign the answer to kth_max.

test_list = [40, 35, 82, 14, 22, 66, 53]


k=2

Subi Subi
Subi Subi
Solution Review: Kth Maximum Integer in a List
The crux of this solution is the sort() method. Once the list is sorted, all we need
to do is identify the correct index. This can be done through [-k] which is
equivalent to [len(test_list)-k].

test_list = [40, 35, 82, 14, 22, 66, 53]


Output
k=2
66
test_list.sort()
kth_max = test_list[-k]
print(kth_max)

Subi Subi
Subi Subi
Exercise: Highs and Lows
You must implement the count_low_high() function. Its parameter is a list
of numbers.

If a number is greater than 50 or divisible by 3, it will count as a high. If


these conditions are not met, the number is considered a low.

At the end of the function, you must return a list that contains the
number of lows and highs, in that order.

In case the list is empty, you may return None.

Take some time to figure out the smartest way


Sample Input
to solve this problem. Python’s built-in functions
num_list = [20, 9, 51, 81, 50, 42, 77] are also available to you. Try using them to
approach and solve this problem.
Sample Output
def count_low_high(num_list):
[2, 5] # 2 lows and 5 highs pass # Replace with your code

Subi Subi
Subi Subi
Solution Review: Highs and Lows
Solution 1 - Using filter and lambda
def count_low_high(num_list):
if (len(num_list)==0):
return None
high_list = list(filter(lambda n: n > 50 or n % 3 == 0, num_list))
low_list = list(filter(lambda n: n <= 50 and not n % 3 == 0, num_list))
return [len(low_list), len(high_list)]

num_list = [20, 9, 51, 81, 50, 42, 77]


print(count_low_high(num_list))

In this solution, the star of the show is the filter() function. We use it to filter all the elements that count
as a high in one list and all the rest in another list.

To count all the elements of both lists, we can simply use the len function.

We didn’t have to use lambdas but they definitely make the code simpler, and that’s what Python is all
about!
Subi Subi
Subi Subi
Solution 2 - List Comprehension
def count_low_high(num_list):
if (len(num_list)==0):
return None
high_list = len([n for n in num_list if n > 50 or n % 3 == 0])
low_list = len([n for n in num_list if n <= 50 and not n % 3 == 0])
return [low_list, high_list]
num_list = [20, 9, 51, 81, 50, 42, 77]
print(count_low_high(num_list))

Instead of using filter and lambda, another neat approach is to use list comprehension to
create our desired lists.

Following the list comprehension syntax, specify the element to be inserted into the new
list, a for loop which iterates the current list, and a condition that needs to be fulfilled.

Going one step further, we can calculate the length of the new list in the same line
Subi Subi
Subi Subi

Libraries

Subi Subi
Subi Subi
What is the Python Standard Library?
The Python Standard Library, PSL, is a collection of pre-defined modules, or
sets of methods which help us perform certain tasks in Python.

The library contains many useful utilities which spare us a lot of time. There are
different sorts of complex mathematical functions, high-level data types,
network programming tools, and this is just the tip of the iceberg!

Generally, a module contains functions


related to a particular aspect of
programming. This makes things easy
because we know which part of our program
requires which module.

In Python, we can make our own modules, but


that’s a story for another time. We’ll be
focusing on what Python offers us
out-of-the-box.
Subi Subi
Subi Subi
Importing a Module
To use the methods of a module, we must import the module into our code. This can be
done using the import keyword.

Let’s import the datetime module which contains several methods related to the current
date and time. As always, these methods can be accessed using the . operator:

# Importing modules at the beginning of the program is a good practice


import datetime
date_today = datetime.date.today() # Current date
print(date_today)
time_today = datetime.datetime.now()
print(time_today.strftime("%H:%M:%S")) # Current time

In the code above, datetime.date and datetime.datetime are classes in the datetime
module. Each class contains its own methods.

Subi Subi
Subi Subi

If we only want a particular class from a module, we can use the from keyword in
the following format:
We can also give our own names to the
from module import class modules that we import by using the as
keyword. Let’s rename datetime to dt and use
from datetime import date it in the program
# Now we only have the methods of the date class import datetime as dt
date_today = date.today() # Current date
print(date_today) date_today = dt.date.today() # Current date
# These won't work print(date_today)
# time_today = datetime.datetime.now()
# print (time_today.strftime("%H:%M:%S"))# Current time
time_today = dt.datetime.now()
print(time_today.strftime("%H:%M:%S")) #
Current time

Subi Subi
Subi Subi
Popular Modules: math
The math module offers a wide range of mathematical functions such as
factorial, trigonometric operations, etc.

import math

fact_of_5 = math.factorial(5) # The factorial of 5


print(fact_of_5)

gcd = math.gcd(300, 90) # Greatest common denominator


print(gcd)

log100 = (math.log(10, 100)) # Logarithm of 10 to the base of 100


print(log100)

To get all math methods for complex numbers, use the cmath module instead.

Subi Subi
Subi Subi
heapq
The heapq module allows us to create the heap data structure. A heap is a
binary tree which always stores a special value at the top (root). A minheap
stores the smallest value at the top and a maxheap stores the largest value at
the top. The pop method returns the value at the top of the heap. Python’s
heapq creates a minheap by default.

import heapq
heap = [] # Empty heap
# Inserting elements in the heap
heapq.heappush(heap, 10)
heapq.heappush(heap, 70)
heapq.heappush(heap, 5)
heapq.heappush(heap, 35)
heapq.heappush(heap, 50)
# Popping the smallest value
minimum = heapq.heappop(heap)
print(minimum)
Subi Subi
Subi Subi
random
The random module is used for generating random numbers in Python. There
are several methods which allow us to generate different types of random
numbers. The random() method generates a random floating-point number
between 0 and 1, whereas uniform() returns a floating-point number within a
custom range.

import random
rand_num = random.random()
print(rand_num)
rand_num_in_range = random.uniform(30, 50) # A random
number between 30 and 50
print(rand_num_in_range)
str_list = ['a', 'b', 'c', 'd', 'e']
random.shuffle(str_list) # Randomly shuffle a list
print(str_list)

Subi Subi
Subi Subi
PyPI
What are Packages?

Python has a standard library that contains many different modules which
serve different purposes. However, we are not limited to these modules.

Developers from all over the world have contributed to increasing the
functionality of Python through packages.

Packages are also collections of modules or smaller packages that assist us in


performing certain tasks. The only difference is that these packages have to be
installed before they can be imported.

All of these packages can be found at the Python Package


Index, PyPI.

There are packages for creating neural networks, text


processing, cryptography, statistical modelling and plotting,
you name it!

Subi Subi
Subi Subi
Popular Packages

Subi Subi
Subi Subi

End of Bootcamp!!!!!

Subi Subi

You might also like