Python for AI 102

Acknowledgement: This post is based mainly on Dr. Quang-Vinh Dinh’s presentation and slides and partly on on TA, STA, and peers’ responses from the course, AIO2025, offered by AI VIETNAM.

Relevance: The audience of this lecture were those who have learned Python for AI 101, had some coding experience, and known a bit of AI knowledge. Absolute beginners are encouraged to read the material and repeatedly practice coding without AI assistance to strengthen their coding and code-reading skills. Note that only necessary Python knowledge is introduced here.

When you get a result that is not what you expect, do not ask for help immediately. Instead, run the code by hand to figure out where your logic breaks, modify the program, and run it again. Repeat this process and your skills will be through the roof at breakneck speed.
-Dr. Quang-Vinh Dinh

In today’s post, we’ll look at common errors and loops in Python.


Common Errors

If you’ve tried some Python exercises, you probably have encountered some of the errors we’ll mention shortly.

NameError

NameError occurs when you try to use a variable or function that hasn’t been defined.

a = 7 
Print(a)

c = a + b
print(c)

def a_function(x): 
    a_variable = 4
    return x * a_variable

print(a_variable)

SyntaxError

SyntaxError occurs when a program violates some grammatical rule of the language.

s = 'Hello World"

print(s)

ZeroDivisorError

ZeroDivisorError occurs when a program tries to perform division by zero, which is mathematically incorrect.

a = 7
b = 0

c = a / b
print(c)

TypeError

TypeError occurs when there is an incompatible data type operation in a program.

a = 5
s = 'AI'

c = a + s
print(c)

IndexError

IndexError occurs when a program attempts to access an element of a collection (a list or string) through an index outside the valid range for that sequence.

a_list = [1, "love", "aivietnam"]

print(a_list[3])

IndentationError

IndentationError signifies the incorrect or inconsistent use of whitespace (spaces or tabs) in a program.

a = 7 
    b = 8

print(b)

ValueError

ValueError occurs when a program attempts to perform an operation on a value that is of correct data type but makes the operation mathematically invalid.

import math

number = -4
print(math.sqrt(number))

ModuleNotFoundError

ModuleNotFoundError occues when a program cannot locate a module that it attempts to import.

import mymodule

print("iloveaivietnam")

RecursionError

RecursionError occurs when a recusive functions calls itself infinitely many times, exceeding Python’s default recusion limit.

def a_function(n):
    return a_function(n)

a_function(7)
Practice Exercises What kind of error in each of the following situation?

print "hello world"


a = 5
Print(a)


import math

number = 220.3
print(math.floor(number)
print(math.pi)


numbers = list(range(10))

for i in numbers:
    if numbers[i] == 5:
        numbers.remove(i)


a = 5
c = a + b
print(c)


s = 'hello world'
print(s[100])


number = 15

if number < 10
    print('A smaller number')
else: 
    print('A larger number')


import torch

print(torch.cuda.is_available())


def a_function(x):
    a_var = 4
    result = x * a_var

    return result

print(a_var)


Suppose we want to draw a million stars. It’d take forever to complete this task unless we, I guess, desire to be professional star drawers. There must be a way to avoid such an endlessly repetitive action. Exactly, it’s a loop, which repeats some action within itself. In Python, there are two types of loops including for and while loops.

For Loop

# code before for

for element in iterable:
    # code inside for

# code after for
flowchart LR
    title[For Loop Flowchart]
    title --> A[start]
    style title fill:#FFF, stroke:#FFF, font-style:italic, font-size:30
    linkStyle 0 stroke:#FFF, stroke-width:0, marker-end:none;

    A --> B{stop condition} 
    B --->|True| C[inside for] --> D[step] --> B
    B ---->|False| E[end for]

    style B fill:#ffdab9
    style C fill:#c6f777
    style D fill:#c6f777
Figure 1. Flowcharts of for loop

A for loop is used when the number of times we want to iterate over a sequence, also known as an iterable.

  • An iterable can be a string, list, dictionary, tuple, and range().
  • An element’s name can be almost anything but is usually i or _.
  • The body must be indented.

For now, we’ll focus on the range(start, stop, step) function.

  • start is $0$ and step is $1$ by default. Passing arguments to these parameters is optional.
  • The stop value is required.
  • The loop runs through a range from start, increases by step, and goes up to but not including stop.

Let’s look at some examples.

range(3) range(1, 8, 3)
Logic flow
  1. range(3) starts at 0, ends by 3, and increases by 1:
    • 0 < 3 True -> add 1 to 0, get 1
    • 1 < 3 True -> add 1 to 1, get 2
    • 2 < 3 True -> add 1 to 2, get 3
    • 3 < 3 False -> stop
    So range(3) contains 0, 1, and 2.
  2. range(1, 8, 3) starts at 1, ends by 8, and increases by 3:
    • 1 < 8 True -> add 3 to 1, get 4
    • 4 < 8 True -> add 3 to 4, get 7
    • 7 < 8 True -> add 3 to 7, get 10
    • 10 < 8 False -> stop
    So range(1, 8, 3) contains 1, 4, and 7.

# repeat 3 times
for i in range(3):
    print(i)

Logic flow
range(3) contains 0, 1, and 2.
  • i = 0 < 3 True -> print(0) -> add 1 to i = 0, get i = 1
  • i = 1 < 3 True -> print(1) -> add 1 to i = 1, get i = 2
  • i = 2 < 3 True -> print(2) -> add 1 to i = 2, get i = 3
  • i = 3 < 3 False -> stop -> display the rendered output
The rendered output is
0
1
2

# repeat 3 times
value = 5
for i in range(3):
    print(value + i)

Logic flow
range(3) contains 0, 1, and 2.
  • i = 0 < 3 True -> print(5 + 0) -> add 1 to i = 0, get i = 1
  • i = 1 < 3 True -> print(5 + 1) -> add 1 to i = 1, get i = 2
  • i = 2 < 3 True -> print(5 + 2) -> add 1 to i = 2, get i = 3
  • i = 3 < 3 False -> stop -> display the rendered output
The rendered output is
5
6
7
Accumulation Pattern for Summation

# repeat 5 times
total = 0
for i in range(5):
    total = total + i
    print(total)

Logic flow
range(5) contains 0, 1, 2, 3, and 4.
  • i = 0 < 5 True -> total = 0 + 0 -> print(0) -> add 1 to i = 0, get i = 1
  • i = 1 < 5 True -> total = 0 + 1 -> print(1) -> add 1 to i = 1, get i = 2
  • i = 2 < 5 True -> total = 1 + 2 -> print(3) -> add 1 to i = 2, get i = 3
  • i = 3 < 5 True -> total = 3 + 3 -> print(6) -> add 1 to i = 3, get i = 4
  • i = 4 < 5 True -> total = 6 + 4 -> print(10) -> add 1 to i = 4, get i = 5
  • i = 5 < 5 False -> stop -> display the rendered output
The rendered output is
0
1
3
6
10
Practice Exercises
Exercise 1: How is this loop different from the summation example?

for i in range(5):
    total = 0
    total = total + i
    
print(total)

Exercise 2: Do these loops calculate the product of numbers from 1 to 5, that is, the factorial of 5? Explain why or why not. How can you make a loop that uses accumulation pattern to compute the product?

product = 0
for i in range(5):
    product = product * i

print(product)


product = 1
for i in range(5):
    product = product * i

print(product)

Exercise 3: What should you pay attention to when applying the accumulation pattern?

While Loops

# code before while

while condition:
    # code inside while

# code after while
flowchart LR
    title[While Loop Flowchart]
    title --> A[start]
    style title fill:#FFF, stroke:#FFF, font-style:italic, font-size:30
    linkStyle 0 stroke:#FFF, stroke-width:0, marker-end:none;

    A --> B{while condition}
    B --->|True| C[inside while] --> B
    B --->|False| D[end while]

    style B fill:#ffdab9
    style C fill:#c6f777
Figure 2. Flowcharts of while loop
  • A while loop is used when we do not know the number of iterations.
  • A while loop runs as long as conditions are fulfilled.

:warning: Always update the condition inside the loop. Or else, we may create/encounter an infinite loop which runs forever unless we force it to quit.


num= 1
a_list = [0, 1, 2]
while True == num in a_list:
    print("helloaivietnam")

    # remove the last time of a_list
    a_list.pop()

Logic flow
  • num = 1 in [0, 1, 2] True -> (True == True) True -> print("helloaivietnam") -> remove 2 -> a_list = [0, 1]
  • num = 1 in [0, 1] True -> (True == True) True -> print("helloaivietnam") -> remove 1 -> a_list = [0]
  • num = 1 in [0] False -> (False == True) False -> go out of loop -> display the rendered output
The rendered output is
helloaivietnam
helloaivietnam

Keywords Used in Loops

break

Imagine playing Where’s Waldo? and we know exactly how many objects there are on the page. Our goal is simple: find Waldo and stop immediately. Also think about a number-guessing game. We’d have to keep guessing until we hit the correct number. The moment we do, the game ends.

In both cases, we need to use a loop to repeat tasks, but a strong command is needed to exit early when the goal is met. That’s where break comes in!

The break keyword is mainly used to terminate a loop regardless of whether a for loop finishes its iterations or a while loop is no longer satisfied. Simply put, when the program hits the break keyword, it breaks out of the loop.

Practice Exercises
Exercise 1: Do these for loops give the same result? Explain why or why not.

for x in range(7):
    print(x)

    if x == 5:
        break

print("iloveaivietnam")


for x in range(7):
    if x == 5:
        break

    print(x)

print("iloveaivietnam")

Exercise 2: Understand this while loop and modify itp to see how many times you need to roll a dice to get a six.

import random

while True:
    roll = random.randint(1, 6)
    print(f"You rolled {roll}.")

    if roll == 6:
        print("You win!")
        break

Exercise 3: Give an example where you can replace a for loop with break with a while loop?
Exercise 4: In which case do you think you have to use while loop with break instead of whle loop? Can you give an example?


continue

Imagine building a machine that scans a conveyor belt of strawberries. The goal is to pick up only the ripe ones and skip the unripe without stopping the belt. Here, a loop goes through every strawberry but magically ignores those unripe. The magic word for this scenario is continue.

The continue keyword is to skip the rest of the current round and jump straight to the next. This keyword is less common than break.

Practice Exercises
Exercise 1: In which case is the continue keyword needed?

for x in range(7):
    print(x)

    if x == 5:
        continue

print("iloveaivietnam")


for x in range(7):
    if x == 5:
        continue

    print(x)

print("iloveaivietnam")

Exercise 2: Rewrite the code of exercise 1 with the while loop.

Examples and Exercises

Estimate the Area of a Unit Circle.
Problem statement: Approximate the area of a unit circle.
Breakdown:
  • $d = 1 - (-1) = 2$ is the diameter of the circle
  • $A_{est}$ is the estimated area of the circle
  • $A_{real}$ is the real area of the circle
  • $f(x) = \pm \sqrt{1 - x^2}$ are the functions of the upper-half and lower-half circles
Idea: Since the area of a circle is twice that of the upper-half circle, we can just focus on the latter. We can break it into smaller pieces in a way that we can compute their area via the function of a half circle.
  1. Divide the upper-half circle into rectangles.
    • Their width is $\Delta{x_i}$.
    • Their height is $f(x_i)$.
    • The number of rectangles is $n = \frac{d}{\Delta{x_i}}$.
    The lower the number of rectangles is, the larger the gap between those rectangles and the circle is and vice versa. In order to reduce the gap, we'll increase the number of rectangles.
  2. Those rectangles roughly cover the half circle, so their area sum is the estimated area of the half circle.
    • $\frac{1}{2} A_{est} = \sum_{i = 1}^{n} f(x_i) \Delta{x_i}$
    • $A_{real} \approx 2 A_{est} = 2 \sum_{i = 1}^{n} f(x_i) \Delta{x_i}$.
This method is called Riemann Sum in Calculus and can be written as follows, $$A_real = \lim_{\Delta{x} \to 0} A_{est} = \lim_{\Delta{x} \to 0} \sum_{i = 1}^{n} f(x_i) \Delta{x_i}$$.
Practice Exercises
Exercise 1: PI Estimation (Gregory-Leibniz Series) $$\text{PI} \approx 4 \sum_{i=1}^{n} \frac{(-1)^{i+1}}{2i-1}$$ Exercise 2: PI Estimation (Nilakantha Series) $$\text{PI} \approx 3 + 4 \sum_{i=0}^{n} \frac{(-1)^{i}}{(2i+2)(2i+3)(2i+4)}$$ Exercise 3: Quadratic Root (Newton Method)
The Newton Method can be used to approximate a root of $f(x) = 0$ by the general formula $$x_{n+1} = x_{n} - \frac{f(x_n)}{f'(x_{n})}.$$ Generate a mathematical formula for $f(x) = x^2 - a$ to approximate $\sqrt{a}$. Rewrite the formula in a programming fashion. Write a function that takes $a$ and $n$ and returns $\sqrt{a}$.
Exercise 4: Write a function the compute the factorial of a positive number using a loop.
Exercise 5: Write a function the compute the factorial of a non-negative number using a loop.
Exercise 6: Give possible mistakes one might make when writing a factorial function.

:speech_balloon: FAQ

Here are some good questions asked during class. The answers to these questions came from either some admin, TA, STA, or members of AIO2025.

Questions Answers
Can I call a function before defining it? No. Python reads code top-down.
Can I write 2 functions A and B where A calls B and B calls A? Why does it give an error when I refer to one before defining it? Yes. Such a situation is called mutual recursion. Python doesn’t execute function definitions which consist of function references. It only starts evaluating when a function is called.
What to do if I want the program to give a warning instead of stopping when it encounters an error? (Like entering a wrong form of email to an app and receiving a warning) You can check out try-except.





    Enjoy Reading This Article?

    Here are some more articles you might like to read next:

  • Python for AI 101
  • Python for AI 103
  • Python for AI 104
  • Math for AI 103
  • Math for AI 101