Python Tutorial: Learn Python Programming from Beginner to Advanced

By khoanc, at: Dec. 21, 2022, 10:46 p.m.

Estimated Reading Time: 54 min read

Python Tutorial: Learn Python Programming from Beginner to Advanced
Python Tutorial: Learn Python Programming from Beginner to Advanced

Python is a powerful and versatile programming language that has gained immense popularity in recent years. It is known for its simplicity, readability, and ease of use, making it an ideal choice for beginners as well as seasoned developers. This tutorial aims to provide a comprehensive introduction to Python, covering topics such as data types, control structures, functions, modules and packages, object-oriented programming, exceptions and error handling, debugging and testing. Whether you're a novice or an experienced programmer, this tutorial will provide you with a solid foundation in Python programming and help you develop the skills to tackle a wide range of projects. So, let's get started!

There are many exercises in this tutorial, and we already provided solutions here


1. Introduction to Python: What, Why, and How

Python is a popular programming language used by developers for a wide range of applications, from web development to machine learning. In this article, we'll explore what Python is, why you should use it, and how to set up your Python environment. Let's get started!


1.1 What is Python?

Python is an interpreted, high-level programming language that was first released in 1991 by Guido van Rossum. Python is known for its simple and readable syntax, which makes it an ideal language for beginners to learn programming. Python's popularity has grown tremendously over the years due to its vast library of modules and its ability to be used for a wide range of applications, such as data analysis, web development, and machine learning.


1.2 Why use Python?

Python has become one of the most popular programming languages in the world, and there are several reasons why you should consider using it. Here are a few key benefits of using Python:

  • Easy to learn: Python's simple and intuitive syntax makes it easy for beginners to learn programming.
  • Wide range of applications: Python can be used for a variety of tasks, such as web development, data analysis, and machine learning.
  • Large community: Python has a large and active community of developers, which means there are plenty of resources available for learning and problem-solving.
  • Open-source: Python is an open-source language, which means that it's free to use and can be modified to fit your specific needs.


1.3 Setting up your Python environment

Before you can start coding in Python, you'll need to set up your Python environment. Here are the basic steps to get started:

  • Download and install Python: You can download the latest version of Python from the official Python website. Once you've downloaded the installer, run it and follow the prompts to install Python on your machine.
  • Choose an editor: Python code can be written in any text editor, but it's often helpful to use an editor specifically designed for Python development, such as PyCharm, VS Code, or Sublime Text.
  • Test your installation: Once you've installed Python and chosen an editor, it's a good idea to test your installation by running a simple "Hello, World!" program.


1.4 The first Python program  - "Hello, World!" Example

"Hello, World!" is a simple program that outputs the message "Hello, World!" to the screen. Here's how you can write and run the program in Python:

Open your text editor and create a new file. Type the following code into the file

print("Hello, World!")


Save the file as "hello.py".

Open a terminal or command prompt and navigate to the directory where you saved the file.

Type and press Enter

python hello.py


You should see the message "Hello, World!" printed to the screen.


2. Variables and Data Types


2.1 Variables

In Python, a variable is a named storage location that stores a value or data. A variable is created when a value is assigned to it using the assignment operator "=".

Here's an example of how to create a variable:

x = 5

In this example, we've created a variable named "x" and assigned the value 5 to it. We can now use the variable "x" in our program to refer to the value 5.


2.2 Data Types

In Python, there are several data types that can be used to represent different kinds of data. The most common data types in Python are:

  • Text Type:  str
  • Numeric Types: int, float
  • Sequence Types: list, tuple
  • Mapping Type: dict
  • Set Types: set
  • Boolean Type: bool
  • None Type:  NoneType

Here's an example of how to create variables of different data types:

a_str = "this is a string"
int_number = 10  # this is an int
float_number = 2.6  # this is a float
a_list = [1, 2, 3]  # this is a list
a_tuple = ((1, 2), (3, 4))  # this is a tuple
a_dict = {"name": "Joe", "age": 10, "male": True, "having_car": None}  # this is a dictionary
a_set = {1, 2, 3, 4}  # This is a set, a set contains unique objects/values
a_bool = True  # this is a boolean
a_none = None


2.3 Type Conversion

In Python, we can convert values from one data type to another using type conversion functions. Here are some common type conversion functions:

  • int() - converts a value to an integer.
  • float() - converts a value to a float.
  • str() - converts a value to a string.
  • bool() - converts a value to a boolean.
  • dict() - converts a value to a dict.
  • list() - converts a value to a list.
  • set() - converts a value to a set.

Here's an example of how to use type conversion functions:

x = 5
y = 3.14
z = "10"

# convert x to a float
x_float = float(x)

# convert y to an integer
y_int = int(y)

# convert z to an integer
z_int = int(z)


2.4 Printing Variables

In Python, we can print the values of variables using the print() function. We can also include text and other values in the output by using string concatenation or string formatting.

Here's an example of how to print variables using string concatenation:

x = 5
y = 3.14
z = "Python"

# print variables using string concatenation
print("x is " + str(x) + ", y is " + str(y) + ", and z is " + z)

# print variables using string formatting
print("x is {}, y is {}, and z is {}".format(x, y, z))

# print variables using f-strings
print(f"x is {x}, y is {y}, and z is {z}")


2.5 Sample Exercises

  1. Write a program that calculates the area of a rectangle. The program should ask the user for the width and height of the rectangle, and then print the area.
  2. Write a program that converts kilometers to miles. The program should ask the user for a distance in kilometers and print the equivalent distance in miles.
  3. Write a program that takes a string as input and prints whether the string contains only digits.
  4. Write a program that takes a list of integers as input and prints the sum of the odd numbers in the list.
  5. Write a program that takes a string as input and prints the number of words in the string.
  6. Write a program that takes a list of strings as input and prints the shortest string in the list.
  7. Create a tuple of your favorite foods and print the length of the tuple.
  8. Create a set of unique numbers from a list of numbers and print the set.
  9. Create a dictionary that maps countries to their capital cities and print the dictionary key and value ordered by key.
  10. Sort a list of strings in alphabetical order and print the sorted list.
  11. Create a list of numbers and calculate the average of the numbers.
  12. Convert a float to an integer and print the integer.
  13. Create a tuple of numbers and check if a specific number is in the tuple.
  14. Create a dictionary of words and their definitions. Print the definition of a specific word.
  15. Sort a list of numbers in descending order and print the sorted list.
  16. Create a set of numbers and remove any even numbers from the set.

Suggested solutions can be found here


3. Operators and Expressions

In Python, operators are symbols or keywords that perform specific operations on variables or values. Expressions are combinations of variables, values, and operators that produce a result. Understanding operators and expressions is essential for writing effective and efficient Python code.


3.1 Arithmetic Operators

Arithmetic operators are used to perform mathematical operations such as addition, subtraction, multiplication, division, modulus, and exponentiation.

Examples:

# Addition
x = 10
y = 5
result = x + y
print(result) # Output: 15

# Subtraction
x = 10
y = 5
result = x - y
print(result) # Output: 5

# Multiplication
x = 10
y = 5
result = x * y
print(result) # Output: 50

# Division
x = 10
y = 5
result = x / y
print(result) # Output: 2.0

# Modulus
x = 10
y = 3
result = x % y
print(result) # Output: 1

# Exponentiation
x = 2
y = 3
result = x ** y
print(result) # Output: 8

 

3.2 Comparison Operators

Comparison operators are used to compare two values and return a boolean value (True or False) based on the result of the comparison.

Examples:

# Equal to
x = 10
y = 5
result = x == y
print(result) # Output: False

# Not equal to
x = 10
y = 5
result = x != y
print(result) # Output: True

# Greater than
x = 10
y = 5
result = x > y
print(result) # Output: True

# Less than
x = 10
y = 5
result = x < y
print(result) # Output: False

# Greater than or equal to
x = 10
y = 5
result = x >= y
print(result) # Output: True

# Less than or equal to
x = 10
y = 5
result = x <= y
print(result) # Output: False


3.3 Logical Operators

Logical operators are used to combine two or more conditions and return a boolean value based on the result of the combination.

Examples:

# AND operator
x = 10
y = 5
z = 8
result = (x > y) and (y < z)
print(result) # Output: True

# OR operator
x = 10
y = 5
z = 3
result = (x < y) or (y > z)
print(result) # Output: True

# NOT operator
x = 10
y = 5
result = not(x > y)
print(result) # Output: False


3.4 Operator Precedence

Operator precedence determines the order in which operators are evaluated in an expression. Operators with higher precedence are evaluated before operators with lower precedence.

Examples:

# Multiplication has higher precedence than addition
result = 10 + 5 * 3
print(result) # Output: 25

# Parentheses can be used to change the order of evaluation
result = (10 + 5) * 3
print(result) # Output: 45

# Comparison operators have higher precedence than logical operators
result = 10 > 5 and 5 < 3
print(result) # Output: False

# Logical operators can be used to combine multiple conditions with different operator precedences
result = (10 > 5) or not(5 < 3) and (4 == 4)
print(result) # Output: True


3.5 Sample Exercises

  1. Write a Python program that takes two integers as input and returns their sum, difference, product, and quotient.
  2. Write a Python program that takes a list of integers and returns the sum of all the even numbers in the list.
  3. Write a Python program that takes a string as input and returns the string in reverse order.
  4. Write a Python program that takes a list of integers and returns the largest and smallest numbers in the list.
  5. Write a Python program that takes a list of strings and returns the number of strings that contain the letter 'a'.
  6. Write a Python program that takes a list of integers and returns a new list containing only the even numbers from the original list.
  7. Write a Python program that takes a string as input and returns the number of vowels in the string.
  8. Write a Python program that takes two lists of integers and returns a new list containing only the common elements between the two lists.
  9. Write a Python program that takes a list of integers and returns a new list containing the square of each number in the original list.
  10. Write a Python program that takes a dictionary as input and returns a new dictionary containing only the key-value pairs where the value is a string.

Suggested solutions can be found here 


4. Control Structures


4.1 Conditional statements (if-else)

Conditional statements are used in programming to check whether a certain condition is true or not. In Python, we use the if and else keywords to create conditional statements.

Example:

age = 25
if age >= 18:
    print("You are an adult")
else:
    print("You are not an adult yet")

 

4.2 Loops (for, while)

Loops are used in programming to iterate over a sequence of values. In Python, we use the for and while keywords to create loops.

Example using for loop:

num_list = [1, 2, 3, 4, 5]
for num in num_list:
    print(num)


Example using while loop:

i = 0
while i < 5:
    print(i)
    i += 1

 

4.3 Control statements (break, continue)

Control statements are used in programming to alter the flow of execution. In Python, we use the break and continue keywords to create control statements.

Example using break:

num_list = [1, 2, 3, 4, 5]
for num in num_list:
    if num == 3:
        break
    print(num)


Example using continue:

num_list = [1, 2, 3, 4, 5]
for num in num_list:
    if num == 3:
        continue
    print(num)


4.4 Sample Exercises

  1. Write a program that prints all the even numbers between 1 and 20 using a for loop
  2. Write a program that prints all the numbers between 1 and 50 that are divisible by 3 or 5 using a while loop.
  3. Write a program that takes a list of numbers and prints only the odd numbers using a for loop.
  4. Write a program that takes a list of names and prints only the names that start with the letter 'S' using a for loop.
  5. Write a program that takes a string and prints the number of vowels in the string using a for loop.
  6. Write a program that takes a list of numbers and returns the sum of all the even numbers using a for loop.
  7. Write a program that takes a list of strings and returns the longest string using a for loop.
  8. Write a program that takes a list of numbers and returns the product of all the numbers using a while loop.
  9. Write a program that takes a list of numbers and returns a new list with only the positive numbers using a for loop.
  10. Write a program that takes a dictionary of items and their prices

Suggested solutions can be found here 
 

5. Functions


5.1 Defining functions

Functions in Python are blocks of code that perform a specific task. They help in organizing code and making it more readable and modular. Defining a function in Python involves using the def keyword followed by the name of the function, followed by parentheses and a colon. The code that belongs to the function is indented.

Example:

def greet(name):
    print(f'Hello, {name}!')


In this example, we define a function called greet that takes one parameter name. The function prints out a greeting using the value of name.


5.2 Parameters and arguments

Parameters are variables that are defined in the function signature and used within the function. Arguments are values passed to a function when it is called.

Example:

def add_numbers(num1, num2):
    sum = num1 + num2
    print(f'The sum of {num1} and {num2} is {sum}')
add_numbers(2, 3)


In this example, we define a function add_numbers that takes two parameters num1 and num2. When the function is called with arguments 2 and 3, the function adds the two numbers and prints out the result.


5.3 Returning values

Functions can also return a value using the return keyword. The returned value can then be used by other parts of the code.

Example:

def multiply(num1, num2):
    product = num1 * num2
    return product
result = multiply(2, 3)
print(result)


In this example, we define a function multiply that takes two parameters num1 and num2. The function calculates the product of the two numbers and returns it. When the function is called with arguments 2 and 3, the returned value is stored in the variable result and then printed out.


5.4 Recursion

Recursion is a technique where a function calls itself to solve a problem. This can be useful in solving problems that can be broken down into smaller, similar subproblems.

Example:

def factorial(num):
    if num == 1:
        return 1
    else:
        return num * factorial(num-1)



result = factorial(5)
print(result)


In this example, we define a function factorial that calculates the factorial of a number using recursion. The base case for the recursion is when num is equal to 1, in which case the function returns 1. Otherwise, the function multiplies num by the factorial of num-1. When the function is called with the argument 5, the result is calculated recursively and stored in the variable result.


5.5 Sample Exercises

  1. Write a function that takes two parameters (a string and a number) and returns the string repeated the specified number of times.
  2. Write a function that takes a list of numbers and returns the sum of all the numbers in the list.
  3. Write a function that takes a list of words and returns the longest word in the list.
  4. Write a function that takes a list of integers and returns a new list with all the even numbers in the original list.
  5. Write a function that takes a string as input and returns a new string with all the vowels removed.
  6. Write a function that takes two parameters (a string and a character) and returns the number of times the character appears in the string.
  7. Write a function that takes a list of strings and returns a new list with all the strings in reverse order.
  8. Write a function that takes two parameters (a list of numbers and a number) and returns the index of the first occurrence of the number in the list. If the number is not in the list, return -1.
  9. Write a function that takes a list of numbers and returns a new list with all the numbers sorted in descending order.
  10. Write a function that takes a string as input and returns a new string with the first letter of each word capitalized.

Suggested solutions can be found here 

 

6. Data Structures

Python provides several built-in data structures that allow you to store collections of data. These data structures include lists, tuples, dictionaries, and sets. Each data structure has its own unique features and use cases.


6.1 Lists

A list is a collection of elements, which can be of any data type, such as integers, strings, or even other lists. Lists are ordered and can be changed (mutable). The syntax for creating a list is to enclose a comma-separated sequence of elements in square brackets.

Example:

my_list = [1, 2, 3, 'hello', [4, 5]]

print(my_list[1]) # Output: 2. List index starts with 0


You can also slice a list using the colon : operator. For example, to get the first three elements of the list:

print(my_list[:3]) # Output: [1, 2, 3]

 
You can add elements to a list using the append() method:

my_list.append('world')
print(my_list) # Output: [1, 2, 3, 'hello', [4, 5], 'world']


You can also remove elements from a list using the remove() method:

my_list.remove(2)
print(my_list) # Output: [1, 3, 'hello', [4, 5], 'world']

 

6.2 Tuples

A tuple is similar to a list, but it is immutable, meaning its contents cannot be changed after creation. Tuples are typically used to group related data together. The syntax for creating a tuple is to enclose a comma-separated sequence of elements in parentheses.

Example:

my_tuple = (1, 2, 'hello')

 
To access an element in a tuple, you can use its index, which starts at 0. For example, to access the second element in the above tuple, you can use:

print(my_tuple[1]) # Output: 2


You can also slice a tuple using the colon : operator. For example, to get the first two elements of the tuple:

print(my_tuple[:2]) # Output: (1, 2)


However, you cannot use remove() function like list


6.3 Dictionaries

Dictionaries in Python are used to store key-value pairs. Each key is unique in a dictionary, and it can be of any data type. The values in a dictionary can be of any data type as well. Dictionaries are created using curly braces ({}) and colons (:) to separate keys and values. Here's an example:

# Creating a dictionary
my_dict = {'apple': 2.50, 'banana': 1.50, 'orange': 3.00}

# Accessing values in a dictionary
print(my_dict['apple']) # Output: 2.50

# Adding a new key-value pair to a dictionary
my_dict['pear'] = 2.00
print(my_dict) # Output: {'apple': 2.50, 'banana': 1.50, 'orange': 3.00, 'pear': 2.00}

# Removing a key-value pair from a dictionary
del my_dict['banana']
print(my_dict) # Output: {'apple': 2.50, 'orange': 3.00, 'pear': 2.00}



6.4 Sets

A set is an unordered collection of unique elements. Sets are created using curly braces ({}) or the set() function. Sets can be used to perform mathematical set operations like union, intersection, and difference. Here's an example:

# Creating a set
my_set = {1, 2, 3, 4}

# Adding elements to a set
my_set.add(5)
print(my_set) # Output: {1, 2, 3, 4, 5}

# Removing an element from a set
my_set.remove(3)
print(my_set) # Output: {1, 2, 4, 5}

# Performing set operations
set1 = {1, 2, 3, 4, 5}
set2 = {3, 4, 5, 6, 7}
print(set1.union(set2)) # Output: {1, 2, 3, 4, 5, 6, 7}
print(set1.intersection(set2)) # Output: {3, 4, 5}
print(set1.difference(set2)) # Output: {1, 2}

 

6.5 Sample Exercises

  1. Write a program that takes a list of integers as input and returns the sum of all even numbers in the list.
  2. Write a function that takes a string as input and returns a dictionary containing the frequency of each letter in the string.
  3. Write a program that takes two lists of integers and returns a new list containing only the elements that are common to both lists.
  4. Write a function that takes a list of strings as input and returns a new list containing only the strings that are palindromes.
  5. Write a program that takes a dictionary of student names and their test scores as input and returns the name of the student with the highest average score.
  6. Write a function that takes a list of integers and a target sum as input and returns a tuple containing two numbers from the list that add up to the target sum.
  7. Write a program that takes a list of strings and sorts them in alphabetical order, ignoring case.
  8. Write a function that takes a list of tuples as input, where each tuple contains a name and an age, and returns a list of names sorted by age in ascending order.
  9. Write a program that takes a list of numbers and returns a new list containing the cumulative sum of the numbers.
  10. Write a function that takes a string as input and returns a new string where each word in the original string is reversed.

Suggested solutions can be found here 
 

7. Input and Output

In Python, input and output (I/O) operations are essential for interacting with the user or reading and writing data to files. In this section, we will cover four subtopics related to I/O operations: reading input from the user, writing output to a file, reading input from a file, and some sample exercises to put your newfound skills to the test.


7.1 Reading input from the user

To read input from the user in Python, we use the input() function. The input() function waits for the user to type in some text and then returns it as a string. Here's an example:

name = input("What is your name? ")
print("Hello, " + name + "!")


In this example, the input() function displays the prompt "What is your name?" and waits for the user to enter their name. The input is then stored in the name variable, and the program prints out a greeting using the print() function.

 

7.2 Writing output to a file

To write output to a file in Python, we use the open() function to create a file object and the write() method to write data to the file. Here's an example:

# Create a file object
file = open("output.txt", "w")

# Write some data to the file
file.write("Hello, world!\n")
file.write("This is some data that we're writing to a file.")

# Close the file
file.close()


In this example, we create a file object named file using the open() function. The second argument to open() is a string that specifies the mode in which we want to open the file. In this case, we use "w" to indicate that we want to write to the file. We then use the write() method to write some data to the file, and we close the file using the close() method.


7.3 Reading input from a file

To read input from a file in Python, we use the open() function to create a file object and the read() method to read data from the file. Here's an example:

# Create a file object
file = open("input.txt", "r")

# Read the entire file
contents = file.read()

# Print the contents of the file
print(contents)

# Close the file
file.close()


In this example, we create a file object named file using the open() function. The second argument to open() is a string that specifies the mode in which we want to open the file. In this case, we use "r" to indicate that we want to read from the file. We then use the read() method to read the entire contents of the file into a variable named contents. Finally, we print the contents of the file and close the file using the close() method.

7.4 Sample Exercises

  1. Write a program that asks the user for their name and age, and then writes this information to a file called "personal_info.txt".
  2. Write a program that reads a file called "numbers.txt" and prints the sum of all the numbers in the file.
  3. Write a program that asks the user for a sentence, and then writes each word of the sentence to a new line in a file called "words.txt".
  4. Write a program that reads a file called "grades.txt" containing the grades of students, and writes to a new file called "passing_grades.txt" only the grades that are above or equal to 60.
  5. Write a program that reads a file called "names.txt" and prints the names in reverse order, separated by commas.
  6. Write a program that asks the user for a filename and prints the number of words in the file.
  7. Write a program that reads a file called "inventory.txt" containing product names and their prices, and prints the name and price of the most expensive product.
  8. Write a program that asks the user for a sentence and prints each word in the sentence along with its length, sorted by length.
  9. Write a program that reads a text file and counts the frequency of each word in the file. The program should then write the word and its frequency to a new file in alphabetical order.
  10. Write a program that reads a CSV file containing information about students (name, age, and grade) and writes a new CSV file containing only the information for students who passed (grade of 60 or higher).

Suggested solutions can be found here


8. Modules and Packages

Python has a large library of modules and packages that can be imported into your code to extend its functionality. In this section, we will cover how to import modules, create your own modules, and install and use packages.


8.1 Importing modules

To use a module in your Python code, you need to import it. The most common way to import a module is using the import statement. Here's an example of how to import the math module:

import math
print(math.pi)  # Output: 3.141592653589793


You can also import specific functions or variables from a module using the from keyword. For example:

from math import pi
print(pi)  # Output: 3.141592653589793


If you want to import everything from a module, you can use the * symbol. However, this is generally not recommended as it can cause namespace collisions and make your code harder to read and debug.

from math import *
print(pi)  # Output: 3.141592653589793



8.2 Creating your own modules

You can create your own modules in Python by writing a Python script and saving it with a .py extension. The functions and variables defined in the script can be accessed from other Python scripts by importing the module.

For example, let's say you have a file named my_module.py with the following contents:

def add_numbers(a, b):
    return a + b


You can import the add_numbers function from my_module in another Python script as follows:

from my_module import add_numbers

result = add_numbers(1, 2)
print(result)  # Output: 3

 

8.3 Installing and using packages

Packages are collections of modules that can be installed using package managers like pip. To install a package, you can use the following command in your terminal:


pip install package_name


Once a package is installed, you can import its modules just like any other module in your code.


8.4 Sample Exercises

  1. Write a Python module that contains a function to calculate the area of a circle given its radius. Import the module into a new Python script and use the function to calculate the area of a circle with radius 5.
  2. Create a Python package called math_operations that contains two modules: addition.py and subtraction.py. Each module should contain a function that takes two numbers as input and returns their sum or difference, respectively. Import the package and use both functions in a new Python script.
  3. Write a Python module called file_operations that contains a function to read a text file and return its contents as a string. Import the module and use the function to read the contents of a text file called sample.txt.
  4. Create a Python package called geometry that contains two modules: shapes.py and transformations.py. The shapes.py module should contain functions to calculate the area and perimeter of a rectangle, and the transformations.py module should contain functions to rotate and translate a rectangle. Import the package and use both modules in a new Python script to calculate the area and perimeter of a rectangle, and then rotate and translate it.

Suggested solutions can be found here


9. Object-Oriented Programming

Object-Oriented Programming (OOP) is a programming paradigm that uses objects to represent and manipulate data. OOP is based on the concepts of classes and objects, which encapsulate data and behavior into a single entity. In this section, we will explore the main concepts of OOP and how they are implemented in Python.


9.1 Classes and Objects

A class is a blueprint for creating objects. It defines the properties and behavior of objects that belong to that class. Objects are instances of a class, and each object has its own set of properties and behavior.

In Python, we define a class using the class keyword, followed by the name of the class and a colon. The properties of the class are defined in the class's methods, which are functions that are defined inside the class.

Here is an example of a simple class:

class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed
    
    def bark(self):
        print("Woof!")


In this example, we define a Dog class that has two properties, name and breed, and a method called bark(). The __init__() method is a special method that is called when an object is created from the class, and it initializes the object's properties.

We can create an instance of the Dog class by calling the class as if it were a function, passing in the necessary arguments:

my_dog = Dog("Fido", "Labrador Retriever")


This creates a new Dog object called my_dog with the name "Fido" and the breed "Labrador Retriever".

We can access the object's properties and methods using the dot notation:

print(my_dog.name)   # Output: Fido
my_dog.bark()        # Output: Woof!


9.2 Encapsulation

Encapsulation is the process of hiding the implementation details of an object from the outside world. This is achieved by defining the object's properties and methods as either public or private.

In Python, we can define a private property or method by prefixing its name with two underscores (__). This will make the property or method inaccessible from outside the class:

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance
    
    def deposit(self, amount):
        self.__balance += amount
    
    def withdraw(self, amount):
        if self.__balance >= amount:
            self.__balance -= amount
        else:
            print("Insufficient funds.")


In this example, the __balance property is private and cannot be accessed directly from outside the class. Instead, we have defined public methods deposit() and withdraw() that allow us to modify the balance.


9.3 Inheritance

Inheritance is one of the key features of Object-Oriented Programming (OOP). It allows a new class to be based on an existing class, inheriting its properties and methods. Inheritance allows code reuse, as it enables you to create a new class that is a modified version of an existing class.

To inherit from a class in Python, you simply define the new class and specify the parent class in parentheses after the class name. The parent class is also known as the superclass or base class, while the new class is known as the subclass or derived class.

Here is an example of inheritance in Python:

class Animal:
    def __init__(self, name, species):
        self.name = name
        self.species = species
    
    def make_sound(self):
        print("Grrr")
        
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name, species="Dog")
        self.breed = breed
    
    def make_sound(self):
        print("Woof")

my_dog = Dog("Rufus", "Labrador")
print(my_dog.name)  # Output: Rufus
print(my_dog.species)  # Output: Dog
print(my_dog.breed)  # Output: Labrador
my_dog.make_sound()  # Output: Woof


In this example, we have defined two classes: Animal and Dog. The Dog class inherits from the Animal class. This means that the Dog class has all the attributes and methods of the Animal class, as well as any additional attributes and methods defined in the Dog class.


9.4 Polymorphism

Polymorphism is the ability of an object to take on many forms. In object-oriented programming, this means that an object can be used in different ways depending on the context in which it is being used. Polymorphism is closely related to inheritance and is often used in conjunction with it.

One example of polymorphism in Python is method overriding. This occurs when a subclass provides a different implementation of a method that is already defined in its superclass. When an object of the subclass is used, the overridden method is called instead of the original method.

Another example of polymorphism in Python is method overloading. This occurs when two or more methods in a class have the same name but different parameters. When a method is called, the correct version of the method is chosen based on the arguments that are passed in.

Here's an example of method overriding:

class Animal:
    def make_sound(self):
        print("The animal makes a sound")

class Cat(Animal):
    def make_sound(self):
        print("Meow")

class Dog(Animal):
    def make_sound(self):
        print("Woof")

# Creating objects of the classes
animal = Animal()
cat = Cat()
dog = Dog()

# Calling the make_sound method on each object
animal.make_sound()  # Output: The animal makes a sound
cat.make_sound()     # Output: Meow
dog.make_sound()     # Output: Woof


In this example, we have a superclass Animal with a method make_sound. The Cat and Dog subclasses both override this method with their own implementation. When we call make_sound on an object of the Animal class, the original implementation is called. When we call make_sound on an object of the Cat or Dog class, the overridden implementation is called instead.

Here's an example of method overloading:

class Math:
    def add(self, x, y):
        return x + y

    def add(self, x, y, z):
        return x + y + z

# Creating an object of the Math class
math = Math()

# Calling the add method with two arguments
print(math.add(2, 3))  # Output: TypeError: add() missing 1 required positional argument: 'z'

# Calling the add method with three arguments
print(math.add(2, 3, 4))  # Output: 9


In this example, we have a Math class with two versions of the add method. One takes two arguments, and the other takes three. When we call add with two arguments, we get a TypeError because the version of the method that takes three arguments is not compatible with only two arguments. When we call add with three arguments, the correct version of the method is called based on the number of arguments.


9.5 Sample Exercises

  1. Create a class called Shape with a method area() that calculates and returns the area of the shape. Then create subclasses Rectangle and Triangle that inherit from Shape and implement their own area() methods.
  2. Create a class BankAccount with methods deposit() and withdraw() that modify the account balance. Then create a subclass SavingsAccount that also has a method add_interest() which adds interest to the account based on the interest rate.
  3. Create a class Animal with a method speak() that prints a generic animal sound. Then create subclasses Dog and Cat that override the speak() method to print the respective animal sound.
  4. Create a class Person with attributes name and age, as well as a method greet() that prints a personalized greeting. Then create a subclass Student that adds an attribute major and overrides the greet() method to include the major in the greeting.

Suggested solutions can be found here

 

10. Exceptions and Error Handling

In Python, exceptions are raised when the interpreter detects an error. Exception handling allows us to handle these errors gracefully and avoid program crashes. In this section, we'll cover the different types of exceptions, how to handle them, and how to raise our own exceptions.


10.1 Types of exceptions

There are many types of exceptions in Python. Some common exceptions include:

  • SyntaxError: Raised when there is a syntax error in the code.
  • NameError: Raised when a variable or function name is not defined.
  • TypeError: Raised when an operation or function is applied to an object of inappropriate type.
  • ValueError: Raised when a function receives an argument of inappropriate value.
  • ZeroDivisionError: Raised when attempting to divide by zero.


10.2 Handling exceptions


Exception handling allows us to handle errors gracefully. We can catch exceptions and perform different actions based on the type of exception. The basic syntax for exception handling is as follows:

try:
    # code that may raise an exception
except ExceptionType1:
    # handle ExceptionType1
except ExceptionType2:
    # handle ExceptionType2
else:
    # code that executes if no exceptions are raised
finally:
    # code that always executes, whether an exception was raised or not


In this syntax, we enclose the code that may raise an exception in a try block. If an exception is raised, we catch it in one or more except blocks. We can have multiple except blocks to handle different types of exceptions. If no exceptions are raised, the code in the else block executes. The code in the finally block always executes, whether an exception was raised or not.


10.3 Raising exceptions

We can raise our own exceptions using the raise statement. The syntax for raising an exception is as follows:

raise ExceptionType("Error message")


Here, we specify the type of exception we want to raise and an error message that describes the exception.


10.4 Sample Exercises

  1. Write a function that takes two numbers as input and divides the first number by the second number. Catch any exceptions that may be raised and print an error message if division by zero occurs.
  2. Write a program that takes a list of numbers as input and calculates the average. If the list is empty, raise a ValueError with the message "List is empty".
  3. Write a function that takes a string as input and returns the reverse of the string. If the input is not a string, raise a TypeError with the message "Input must be a string".
  4. Write a program that reads a file and prints the contents. If the file cannot be opened, catch the exception and print an error message.

Suggested solutions can be found here


11. Debugging and Testing

When writing code, it's inevitable that you will encounter bugs and errors that need to be fixed. Debugging is the process of identifying and fixing these issues in your code. Testing is the process of verifying that your code works as expected and meets the requirements.


11.1 Debugging techniques

Debugging can be a challenging task, but there are several techniques and tools available to help you identify and fix issues in your code:

  • Print statements: One of the simplest debugging techniques is to add print statements to your code to display the values of variables and other data at specific points in the program.
  • Debugger: A debugger is a tool that allows you to step through your code line by line, set breakpoints, and examine the values of variables and other data in real-time. Famous tools would be ipdb, pdb and breakpoint()
  • Logging: Logging is a technique that involves writing messages to a log file or console to track the flow of your program and diagnose issues.
  • Code analysis tools: There are various code analysis tools that can help you find common issues such as syntax errors, unused code, and potential performance issues.


11.2 Testing frameworks

Testing frameworks provide a set of tools and functions to help you write automated tests for your code. These tests can be run regularly to ensure that your code continues to work as expected and to catch any regressions that might have been introduced during development.

There are several popular testing frameworks available in Python, including:

  • unittest: The built-in unittest module provides a framework for writing and running tests for your code.
  • pytest: Pytest is a popular third-party testing framework that provides a more concise syntax and additional features for writing tests.
  • nose: Nose is another third-party testing framework that is compatible with unittest-based tests and provides additional functionality such as test discovery and plugin support.


11.3 Sample Exercises

Here are four sample exercises to practice debugging and testing:

  1. Write a function that takes a string as input and returns True if the string is a palindrome (reads the same forwards and backwards), and False otherwise. Write a test function that verifies that the function returns the correct result for several test cases.
  2. Write a function that takes a list of integers and returns the maximum value in the list. If the list is empty, the function should raise a ValueError. Write a test function that verifies that the function raises the expected exception when called with an empty list.
  3. Write a function that takes two numbers as input and returns their product. If either of the inputs is not a number, the function should raise a TypeError. Write a test function that verifies that the function raises the expected exception when called with non-numeric inputs.
  4. Write a function that takes a list of integers and returns a new list containing only the even numbers. Write a test function that verifies that the function returns the expected result for several test cases.

Suggested solutions can be found here


12. Conclusion

In conclusion, Python is a powerful programming language that can be used for a variety of applications. In this tutorial, we have covered the basics of Python, including data types, control structures, functions, modules, and object-oriented programming. We have also discussed common programming concepts such as debugging and testing.

To continue learning Python, there are many great resources available. Here are some recommendations:

Learning Python:

  • Python.org (official website with documentation and tutorials)
  • Codecademy (interactive online course)
  • Coursera (online courses from universities and organizations)

Good blog posts:

Practicing sites:

By continuing to practice and explore Python, you can unlock its full potential and create amazing projects.


Subscribe

Subscribe to our newsletter and never miss out lastest news.