Programming Session 0#

Goals#

  • Understanding fundamentals of Python programming:

  • Variables, data types, lists, sets and tuples.

  • Conditional expressions and loops

  • Sort

  • Dictionary

  • Files and user interaction

  • Mathematical (matrix) calculations using Numpy

Exercise 1 ★#

1. Comments#

The # symbol is used for writing a comment.

# This is a comment
print("Hello")

2. Variables#

A variable is a symbolic name that references or holds a value, which can be of various data types such as numbers, strings, or objects.

# a variable
message = "World!"
print(message)

Variables are used to store values that can be manipulated; here, a and b are assigned integer values, and c stores the result of their addition, which is then printed.

a = 10
b = 20
c = a + b
print(c)

A variable is assigned a floating-point value and then printed.

# floating point numbers
pi = 3.14
print(pi)

The type() function in Python is used to determine the data type of a variable or a value.

# data types
message1 = "Hello"
a = 12
pi = 3.14
print(type(message1))
print(type(a))
print(type(pi))

3. Concatenation of two strings#

String concatenation in Python refers to the process of joining multiple strings together to create a new string. This can be achieved using the + operator. When you use + between two strings, Python combines them into a single string.

# concatenation of two strings
message = "World!"
print("Hello" + message)
# concatenation of two strings using variables
message1 = "Hello "
message2 = "World!"
print(message1 + message2)
# concatenation involving two variables of different data types
# operation + on two different data types

# Uncomment the print statement and run the code
message1 = "Hello! Python"
a = 3
# print(message1 + a)

Why did you get this error? In the following code, we correct this error.

# concatenation solution involving two variables of different data types
message1 = "Hello! Python "
a = 3
print(message1 + str(a))

Type conversion (or type casting) refers to the process of converting one data type into another.

str(a) converts the integer variable a into a string. This is necessary because you cannot directly concatenate a string (message1) with an integer (a) using the + operator without first converting the integer to a string.

4. Lists#

A list is a collection of items, which can be of different data types, enclosed in square brackets [] and separated by commas.

a = [10, 20, 30, 40, 50]
print(a)

Lists are ordered collections, and each element in a list has a specific position called an index. Indexing allows you to access individual elements in a list using their position.

The index of the first element in a list is 0, the index of the second element is 1, and so on.

Elements in a list can be accessed by specifying the list’s name followed by square brackets containing the index of the element you want to access.

a = [10, 20, 30, 40, 50]
print(a[0])
print(a[1])
print(a[2])
print(a[3])
print(a[4])
# Uncomment the print statement and run the code
a = [10, 20, 30, 40, 50]
# print(a[8])

Why did you get this error? The error occurs because the code is attempting to access an element in the list a at index 8, which does not exist. In Python (and in many programming languages), indexing of lists starts at 0 and goes up to len(a) - 1, where len(a) is the number of elements in the list a.

message1 = "Hello! Python "
print(message1[0])
print(message1[1])
print(message1[2])
print(message1[3])
print(message1[4])
print(message1[5])
print(message1[6])
print(message1[7])

Strings behave like lists of characters in many respects, so you can access individual characters using indexing just like you would with elements in a list. The len() function is used to determine the number of characters (or elements) in the string (or list).

message1 = "Hello! Python "
print(len(message1))

We’ll now create a list of integers.

a = [10, 20, 30, 40, 50]
print(len(a))

The len() function is used to determine the number of elements in a list (or the length of any iterable object). When len() is applied to a list, it returns the number of elements (or items) present in that list.

a = [10, 20, 30, 40, 50]

# add a new number at the end of the list
a.append(60)
print(a)

The append() method is used to add a single element to the end of an existing list. The syntax for using append() is list_name.append(element), where list_name is the name of the list to which you want to add the element, and element is the item you want to add. The element can be of any data type, and it is added as the last item in the list.

Elements in a list can be modified by assigning a new value to a specific index. List indexing starts at 0, so a[0] refers to the first element of the list a, a[1] refers to the second element, and so on. You can directly assign a new value to any existing element in the list using this indexing method.

a = [10, 20, 30, 40, 50]

# modify a number at a particular index
a[0] = 0
print(a)

Uncomment the assignment statement and run the code below.

a = [10, 20, 30, 40, 50]
# a[6] = 20
print(a)

Why did we get this error? We are modifying an element at a non-existing index.

The insert() method is used to insert an element into a list at a specified index. The syntax for insert() is list_name.insert(index, element), where list_name is the name of the list, index is the position where you want to insert the element, and element is the item you want to insert.

Elements after the specified index are shifted to the right to accommodate the new element.

a = [10, 20, 30, 40, 50]

# inserting an element at a particular index will modify the list
a.insert(0, 0)
print(a)
print(len(a))
a = [10, 20, 30, 40, 50]
a.insert(6, 60)
print(a)
print(len(a))
a = [10, 20, 30, 40, 50]

# We will now try to insert a number at an index greater than the length
# of the list. We will see that we do not get any error and the new number
# is added at the end of the list
a.insert(10, 60)
print(a)
print(len(a))

The insert() method can be used to insert an element at any index within the current range of the list. If you specify an index that is greater than the current length of the list, Python will insert the new element at the end of the list.

5. Tuples (non-modifiable lists)#

A tuple is an ordered collection of elements, similar to a list, but tuples are immutable, meaning their contents cannot be changed after creation. Tuples are defined using parentheses () and elements are separated by commas. Tuples can contain elements of different data types and can even hold other tuples.

a = (10, 20, 30, 40, 50)
print(a)
a = (10, 20, 30, 40, 50)
print(a[0])
a = (10, 20, 30, 40, 50)

# We now try to modify a tuple
# Uncomment the code below and run the code
# A tupe is a non-modifiable list

# a[0] = 0
print(a)

Tuples in Python are immutable, meaning their contents cannot be changed after they are created. This is in contrast to lists, which are mutable and allow modifications to their elements.

6. Sets#

A set is an unordered collection of unique elements. It does not allow duplicate elements. Sets are defined using curly braces {}, and elements are separated by commas.

When you create a set with duplicate elements, Python automatically removes the duplicates, leaving only unique elements in the set.

# A set is a collection of distinct elements
a = {10, 20, 30, 40, 50, 10, 20, 30, 40, 50}
print(a)

You can add elements to a set using the add() method and remove elements from a set using the remove() method.

a = {10, 20, 30, 40, 50, 10, 20, 30, 40, 50}
a.add(10)
print(a)
a = {10, 20, 30, 40, 50, 10, 20, 30, 40, 50}
a.add(60)
print(a)
a = {10, 20, 30, 40, 50, 10, 20, 30, 40, 50}
a.remove(40)
print(a)

We will now try different data types with the numbers and print the result

# set
a = {10, 20, 30, 40, 50, 10, 20, 30, 40, 50}
print(a)
print(type(a))

# tuple
b = (10, 20, 30, 40, 50, 10, 20, 30, 40, 50)
print(b)
print(type(b))

# list
c = [10, 20, 30, 40, 50, 10, 20, 30, 40, 50]
print(c)
print(type(c))

Sets in Python automatically remove duplicates. Tuples preserve the order of elements and allow duplicates, but are immutable. Lists also preserve the order of elements and allow duplicates.

union()#

The union() method or the | operator combines two sets into a new set that contains all unique elements from both sets. It returns a new set containing elements that are present in either a, b, or both, without duplicates. The union operation does not modify the original sets a and b; instead, it creates and returns a new set with the combined elements.

a = {10, 20, 30, 40, 50}
b = {10, 60, 70, 80, 90}
c = a.union(b)
print(c)

intersection()#

The intersection() method or the & operator returns a new set containing elements that are present in both sets a and b. It computes the intersection of sets a and b, meaning it includes only elements that are common to both sets.

The intersection operation does not modify the original sets a and b; instead, it creates and returns a new set with the common elements.

a = {10, 20, 30, 40, 50}
b = {10, 60, 70, 80, 90}
c = a.intersection(b)
print(c)

difference()#

The difference() method or the - operator returns a new set containing elements that are present in set a but not in set b. It computes the difference between sets a and b, meaning it includes only elements from a that are not present in b. The difference operation does not modify the original sets a and b; instead, it creates and returns a new set with the elements from a that are not in b.

a = {10, 20, 30, 40, 50}
b = {10, 60, 70, 80, 90}
c = a.difference(b)
print(c)
a = {10, 20, 30, 40, 50}
b = {10, 60, 70, 80, 90}
c = b.difference(a)
print(c)

Exercise 2 ★#

1. Conditional Expressions#

Conditional statements (if, else, elif) allow you to control the flow of your program based on certain conditions. These statements help you execute specific blocks of code depending on whether conditions are True or False.

The if statement#

The if statement is used to execute a block of code only if a specified condition is True. It can be followed by an optional else block.

a = 12
if a % 2 == 0:
    print(a, " is divisible by 2")
else:
    print(a, " is not divisible by 2")
lang = "Français"
if lang == "Français":
    print("Bonjour World!!")
else:
    print("Hello World!")

The if-elif-else statement#

The if-elif-else statement is used when you have multiple conditions to evaluate sequentially. It allows you to check for multiple conditions and execute a block of code as soon as one of the conditions is True. It can also have an optional else block at the end.

Syntax:

if condition1:
    # block of code to execute if condition1 is True
elif condition2:
    # block of code to execute if condition2 is True (optional)
elif condition3:
    # block of code to execute if condition3 is True (optional)
else:
    # block of code to execute if all conditions are False (optional)
b = 15

if b < 10:
    print("b is less than 10")
elif b == 10:
    print("b is equal to 10")
else:
    print("b is greater than 10")

The if-elif statement (without else)#

You can also use if-elif without an else block. In this case, if none of the conditions are True, no block of code will be executed.

Syntax:

if condition1:
    # block of code to execute if condition1 is True
elif condition2:
    # block of code to execute if condition2 is True (optional)
c = 5

if c < 0:
    print("c is negative")
elif c == 0:
    print("c is zero")
elif c > 0:
    print("c is positive")

Key Points:#

  • Use if to execute a block of code based on a single condition.

  • Use if-elif-else to evaluate multiple conditions sequentially and execute the corresponding block of code as soon as one condition is True.

  • Use if-elif without else when you have multiple conditions to check, but you do not need to execute any code if none of the conditions are True.

  • Indentation is crucial in Python to denote blocks of code within conditional statements.

Conditional statements are fundamental for controlling the logic and behavior of your Python programs based on different scenarios and conditions.

2. Loops#

Loops can also be used to access the elements at different indices. A for loop is used to iterate over a sequence (e.g., a list, tuple, string, or range). The loop variable (i in this case) takes on each element of the sequence one by one, allowing you to perform operations on each element inside the loop.

for i in [10, 20, 30, 40, 50, 10, 20, 30, 40, 50]:
    print(i)
for i in (10, 20, 30, 40, 50, 10, 20, 30, 40, 50):
    print(i)
for i in {10, 20, 30, 40, 50, 10, 20, 30, 40, 50}:
    print(i)

3. Range#

The range(start, stop) function generates a sequence of numbers starting from start up to (but not including) stop.

for i in range(0, 10):
    print(i)

range(start, stop, step) specifies the increment (or decrement) between each number in the sequence.

for i in range(0, 10, 2):
    print(i)

When the step value is negative (-2 in the case below), the sequence counts downwards.

for i in range(10, 0, -2):
    print(i)
for i in range(10, 0):
    print(i)

print() by default displays the message followed by a new line But you can change its behaviour. The end=" " parameter in print() specifies that each print statement should end with a space instead of the default newline character (\n).

for i in range(0, 10, 2):
    print(i, end=" ")

4. split()#

The split() function in Python is used to split a string into a list of substrings based on a specified delimiter. If no delimiter is specified, by default, it splits the string based on any whitespace characters (spaces, tabs, newlines).

for i in "Hello, World!".split():
    print(i)

The for loop iterates over each element in the list produced by split(), allowing you to process each substring individually.

for i in "Hello, World!".split(","):
    print(i)

Question: Write a program in Python to display the following output

1

12

123

1234

12345

123456

1234567

12345678

Exercise 3 ★#

1. Sort#

The sort() method is used to sort lists. By default, sort() arranges elements in ascending order.

num = [10, 20, 30, 40, 50, 10, 20, 30, 40, 50]
num.sort()
print(num)

2. Sort (decreasing order)#

Passing reverse=True sorts elements in descending order. The sort() method modifies the list directly without returning a new list.

num = [10, 20, 30, 40, 50, 10, 20, 30, 40, 50]
num.sort(reverse=True)
print(num)

3. minimum#

The min() function returns the smallest element in a sequence. It can be used directly with lists (or other iterables) to find the smallest element.

num = [10, 20, 30, 40, 50, 10, 20, 30, 40, 50]
print(min(num))

4. maximum#

The max() function returns the largest element in a sequence. It can be used directly with lists (or other iterables) to find the largest element.

num = [10, 20, 30, 40, 50, 10, 20, 30, 40, 50]
print(max(num))

5. sorted()#

The sorted() function in Python can be used to create a new sorted list without modifying the original list. It allows you to obtain a sorted version of a list without altering the original list.

This approach is useful when you need both the original unsorted list and a sorted version for different purposes.

num = [70, 20, 30, 10, 50, 60, 20, 80, 70, 50]
sortednum = sorted(num, reverse=True)
print(num)
print(sortednum)

Question : Modify the code given below to display the five greatest unique numbers.

num = [70, 20, 30, 10, 50, 60, 20, 80, 70, 50]

# select first five numbers
sortednum = sorted(num, reverse=True)[:5]
print(sortednum)

6. reversed()#

The reversed() function reverses the order of elements in a sequence without modifying the original list. The result of reversed() is an iterator, which means it generates elements lazily as needed.

a = [12, 13, 14, 15]
a_reverse = reversed(a)

print(a_reverse)

for num in a_reverse:
    print(num)

7. zip()#

The zip() function pairs elements from multiple iterables (lists, tuples, etc.) based on their positions. If the input iterables (a1 and b1 in the example below) have different lengths, zip() stops after the shortest one is exhausted.

zip() is commonly used for iterating over multiple lists simultaneously or for combining data from different sources into tuples.

a1 = [1, 2, 3, 4]
b1 = [5, 6, 7, 8]

zipped = list(zip(a1, b1))
print(zipped)

8. enumerate()#

The enumerate() function in Python is used to add a counter to an iterable object (like a list, tuple, or string) and return it as an enumerate object.

This enumerate object can then be used in loops or other iterations to obtain an indexed list of elements.

a1 = [1, 2, 3, 4]

ezipped = enumerate(a1)
print(ezipped)
a1 = [1, 2, 3, 4]

ezipped = enumerate(a1)
for index, number in ezipped:
    print(index, number)

It can also be used with other functions seen above.

a1 = [1, 2, 3, 4]
b1 = [5, 6, 7, 8]

ezipped = list(enumerate(zip(a1, b1)))
print(ezipped)

9. Working with Strings#

We can also use these functions for working with strings.

print(sorted("Hello World!".split(), key=str.lower, reverse=True))
days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
days_num = list(enumerate(days))
print(days_num)

enumerate(days, start=1) creates an enumerate object that iterates over days, starting the index from 1 (start=1).

days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

days_num = list(enumerate(days, start=1))
print(days_num)

Exercise 4 ★★#

1. Dictionary#

Dictionary represents an unordered collection of items where each item is a key-value pair. Keys must be unique and immutable (strings, numbers, tuples), while values can be of any data type and mutable.

a = {"joyful": 12, "happy": 12, "sad": 2}
print(a)
print(type(a))

You can access (and even modify) the value associated with a key using a[key].

a = {"joyful": 12, "happy": 12, "sad": 2}
a["joy"] = 10
print(a)

Iterating over a dictionary directly iterates over its keys by default.

a = {"joyful": 12, "happy": 12, "sad": 2}
for key in a:
    print("The word ", key, " appears ", a[key], " times")

Directly sorting a dictionary with sorted() sorts its keys and returns them as a list.

words = {"joyful": 12, "happy": 12, "sad": 2, "joy": 10}
print(sorted(words))

Using .items() allows you to iterate over key-value pairs of a dictionary.

a = {"joyful": 12, "happy": 12, "sad": 2}
for key, value in a.items():
    print("The word ", key, " appears ", value, " times")

You can delete an item from a dictionary using del followed by a[key], where key is the key of the item you want to delete.

a = {"joyful": 12, "happy": 12, "sad": 2}
del a["sad"]
print(a)
words = {"joyful": 12, "happy": 12, "sad": 2, "joy": 10}
words_tuple = [(key, value) for key, value in words.items()]
print(words_tuple)

2. itemgetter#

itemgetter is a function from the operator module that is used to retrieve items or elements from an iterable object (like a list, tuple, or dictionary) based on their indices or keys. It returns a callable object that fetches the given item(s) from the provided object.

Using sorted() with itemgetter(1) allows sorting a list of tuples by the second element (value in this case). Sorting operations do not modify the original dictionary or its contents but create a sorted list of tuples.

from operator import itemgetter

words = {"joyful": 12, "happy": 12, "sad": 2, "joy": 10}
words_tuple = [(key, value) for key, value in words.items()]
print(sorted(words_tuple, key=itemgetter(1)))

3. Interaction with user#

The input() function is used to accept user input from the console. The message inside input() serves as a prompt to guide the user on what to input.

# name = input("What is your name?")
# print(name)
# age = input("How old are you? ")
# print(age)
# print(type(age))
# age = input("How old are you?")
# age = int(age)
# print(age)
# print(type(age))

Question: Write a program in Python that interacts with the user to obtain the following information of 5 students:

  • Name of student

  • Age

  • Grades in 5 modules

Once the information for all the five students is obtained, calculate and display the following values for every module:

  • average grade

  • maximum grade

  • minimum grade

Exercise 5 ★★★#

1. Files#

The open() function opens a file and returns a corresponding file object that allows you to interact with the file (read from it, write to it, etc.). The read() method reads data from an opened file. The write() method writes data to an opened file.

message = "Hello World!"
with open("Hello.txt", "w") as file:
    file.write(message)
file.close()
with open("Hello.txt", "r") as file:
    text = file.read()
    print(text)
file.close()

In Jupyter Notebook, the ? symbol is used to access documentation and help for functions and objects. It is a shortcut to access the built-in help system in Python and Jupyter environments.

message1 = "Hello World!"
message2 = "Programming in Python"
with open("Hello.txt", "w") as file:
    file.write(message1)
    file.write(message2)
file.close()
message1 = "Hello World!\n"
message2 = "Programming in Python"
with open("Hello.txt", "w") as file:
    file.write(message1)
    file.write(message2)
file.close()

with open("Hello.txt", "r") as file:
    text = file.read()
    print(text)
file.close()
?open
?message1
?message2
with open("Hello.txt", "r") as file:
    text = file.read()
    print(text)
file.close()

2. readline()#

This function can be used to read a file line by line and not the complete happy in a single call like read()

message1 = "Hello World!\n"
message2 = "Programming in Python"
with open("Hello.txt", "w") as file:
    file.write(message1)
    file.write(message2)
file.close()

Use readline() in a loop or iteratively to process each line of a file sequentially. It is useful for handling large files or files where processing each line independently is necessary.

with open("Hello.txt", "r") as file:
    text = file.readline()
    print(text)
file.close()
message1 = "Hello World!\n"
message2 = "Programming in Python\n"
with open("Hello.txt", "w") as file:
    file.write(message1)
    file.write(message2)
file.close()
with open("Hello.txt", "r") as file:
    for line in file:
        print(line)
file.close()

Question: Copy any HTML file in your home directory. Write a program in Python to get the following values:

  • number of characters in the HTML file

  • number of lines in the HTML file

  • number of words in the HTML file

  • first twenty words in the HTML file

  • distinct words in the HTML file

Question: Copy the CSV file population.csv from the data folder. The file contains the population values between 1901 and 2016. Write a program in Python to get the maximum value.

  • the maximum value of population

  • the minimum value of population

Exercise 6 ★#

NumPy, a popular library for numerical computations, provides efficient ways to perform mathematical operations on arrays, including matrices. NumPy operations are optimized for performance, especially with large datasets.

1. Importing Numpy#

import numpy as np

2. Matrix operations#

a1 = [1, 2, 3, 4]
b1 = [5, 6, 7, 8]

Matrix addition using np.add()

c1 = np.add(a1, b1)
print(c1)

Matrix subtraction using np.subtract()

c1 = np.subtract(a1, b1)
print(c1)

Matrix multiplication using np.multiply()

c1 = np.multiply(a1, b1)
print(c1)
c1 = np.multiply(4, b1)
print(c1)
c1 = np.dot(a1, b1)
print(c1)
c1 = np.dot(5, b1)
print(c1)
b1 = [5, 6, 7, 8]
c1 = np.dot(a1, b1)
print(c1)
a1 = [1, 2, 3, 4, 5, 6]
moyen = np.average(a1)
print(moyen)

3. Matrix Transposition#

b1 = [[5, 6, 7, 8, 9], [1, 2, 3, 4, 5]]
print(b1)
b1 = np.array(b1)
print(b1.T)

4. Split a matrix to two, horizontally and vertically#

np.hsplit() function splits an array horizontally (along columns) at the specified indices.

a = [[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 1]]
a = np.array(a)

# Split 'a' horizontally at column index 2
a = np.hsplit(a, [2])

a1 = a[0]
a2 = a[1]
print(a1)
print(a2)
?np.hsplit

np.vsplit() function splits an array vertically (along rows) at the specified indices.

a = [[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 1]]
a = np.array(a)

# Split 'a' vertically at row index 2
a = np.vsplit(a, [2])

a1 = a[0]
a2 = a[1]
print(a1)
print(a2)

5. Operations on two-dimensional matrices#

a2 = [[1, 2, 3, 4], [1, 2, 3, 4]]
b2 = [[5, 6, 7, 8], [5, 6, 7, 8]]
c2 = np.add(a2, b2)
print(c2)
c2 = np.subtract(a2, b2)
print(c2)
c2 = np.multiply(a2, b2)
print(c2)
a2 = [[1, 2, 3, 4], [1, 2, 3, 4]]
a2 = np.array(a2)
b2 = [[5, 6, 7, 8], [5, 6, 7, 8]]
b2 = np.array(b2)
c2 = np.dot(a2, b2.T)
print(c2)

6. Change the shape of a matrix#

b2 = [[5, 6, 7, 8], [5, 6, 7, 8]]
b2 = np.array(b2)
print(b2)
c2 = b2.reshape(4, 2)
print(c2)

7. Creation of a matrix with random numbers#

a = np.random.rand()
print(a)
a = np.random.rand(1)
print(a)
a = np.random.rand(2, 5)
print(a)
a = np.random.rand(2, 3, 3)
print(a)
a = np.zeros(1)
print(a)
a = np.zeros(1, dtype=int)
print(a)
a = np.zeros((2, 5), dtype=int)
print(a)