Loops
Comparison and logical operators
Conditionals
It is rarely useful that a computer performs each operation only once; we usually need it to repeat what it does. To do so, we need loops.
for
-loopsThe most common one is a for
-loop, which is usually used to execute some part of the code a predetermined number of times (although, it can be used on a wider range of applications in many C-like languages).
In Python 3, we often use the for
-loop together with the range
function which pretends to return a list of numbers (it returns something more complex, we can consider it a list for now). That function can be called as follows:
range(n)
-- numbers $0, 1, \dots, n \color{red}{-1}$;range(m, n)
-- numbers $m, m+1, \dots, n \color{red}{-1}$;range(m, n, s)
-- numbers $m, m+s, \dots, m + sk$, where $k \in \mathbb{N}$ such that $m + sk \color{red}{<} n \le m + s(k+1)$.Do not forget that the ending is not included, hence "$\color{red}{-1}$"!
Python 2 remark: In Python 2, range
actually returns a list. The exact equivalent to range
from Python 3 is called xrange
in Python 2.
In [1]:
for i in range(5):
print("Hello, World!")
In [2]:
i = 0
print("Hello, World!")
i = 1
print("Hello, World!")
i = 2
print("Hello, World!")
i = 3
print("Hello, World!")
i = 4
print("Hello, World!")
Obviously, we don't need the variable i
, but it's part of the loop. If we want to ignore it, we can use the underscore _
instead:
In [3]:
for _ in range(5):
print("Hello, World!")
This is the same as
In [4]:
print("Hello, World!")
print("Hello, World!")
print("Hello, World!")
print("Hello, World!")
print("Hello, World!")
for
-loop syntaxfor
-loops have the following elements:
_
" if we don't need those values),Do not forget the colon! That will make Python somewhat nervous...
Notice the indentation in the second line:
In [5]:
for i in range(5):
print("Hello, World!")
All the commands with the same indentation "belong" to that loop. Observe the difference:
In [6]:
print("The first loop:")
for i in range(3):
print("Inside loop.")
print("And where is this? Inside or outside of the loop?")
print()
print("The second loop:")
for i in range(3):
print("Inside loop.")
print("And where is this? Inside or outside of the loop?")
How would we do it manually?
Since computers prefer to know in advance that we wish to loop through some of the code, we shall rearrange the above (i.e., put the item 5 where the loop starts):
We are now ready for a Python code:
In [7]:
n = int(input("How many numbers do you want to summarize? "))
s = 0
for i in range(n):
x = float(input("Input a_" + str(i+1) + ": "))
s += x
print(s)
In the above code, we use the variable i
to explain to the user which number they have to input. However, since range(n)
traverses through numbers $0, 1, \dots, n-1$ and we want then to be $1, 2, \dots, n$, we used i+1
for such a description.
We can avoid this extra addition by simply explaining to the range()
function that we want the numbers to start from $1$ and go up to $n$ (i.e., numbers from $1$, strictly smaller than $n+1$):
In [8]:
n = int(input("How many numbers do you want to summarize? "))
s = 0
for i in range(1, n+1):
x = float(input("Input a_" + str(i) + ": "))
s += x
print(s)
Usually, the first approach is better because indexing of lists (we'll get to them later) is zero-based and you'll almost always want your loop counter to respect that.
while
-loopsIt is not always known ahead of the execution how many times the loop will have to repeat its block. For example:
Equivalent to the basic for
-loop,
In [9]:
n = int(input("n = "))
for i in range(n):
print(i)
is the following code:
In [10]:
n = int(input("n = "))
i = 0
while i < n:
print(i)
i += 1
Let us, as before, read the above code as if it was a sentence in regular English language, taking into account that i += 1
stands for "add 1 to i
", i.e., "increase i
by 1":
While $i$ is less than $n$, print $i$ and increase it by one.
And this is exactly how while
-loops work:
In [11]:
i = 0
while i < 2:
print("Before the increment:", i)
i += 1
print("After the increment:", i)
So, even after i
took the value 2 (thus, making the condition i < 2
false), the body still executed until the end, before rechecking the condition and terminating the loop!
These are the comparison operators that can be used on numbers (and some other types, for example strings):
Operator | Example | Meaning |
---|---|---|
< |
a < b |
The value of a is smaller than the value of b |
<= |
a <= b |
The value of a is smaller than or equal to the value of b |
> |
a > b |
The value of a is bigger than the value of b |
>= |
a >= b |
The value of a is bigger than or equal to the value of b |
== |
a == b |
The value of a is equal to the value of b (but not necessarily identical!) |
!= |
a != b |
The value of a is not equal to the value of b |
is |
a is b |
a and b are exactly the same object |
not is |
a is not b |
a and b are not exactly the same object |
or |
a or b |
a is true or b is true (or both); a and b can be non-Boolean values |
and |
a and b |
Both a and b are true; a and b can be non-Boolean values |
not |
not a |
True if a is false; False otherwise; a can be a non-Boolean value |
When checking if the value of a variable x
is undefined (i.e., it is None
), always use x is None
or x is not None
, and not x == None
or x != None
(the reasons are quite technical and far beyond the scope of this course; those interested can read more about the subject here).
Also, do not use not x is None
or not (x is None)
; instead, use a much more readable x is not None
.
In [12]:
print("1 < 2:", 1 < 2)
print("1 < 1:", 1 < 1)
print("2 < 1:", 2 < 1)
In Python, we can also use
a < b < c
as a shorthand for
a < b and b < c
and
a < b > c
as a shorthand for
a < b and b > c
as shown below:
In [13]:
print("1 < 2 < 3:", 1 < 2 < 3)
print("1 < 2 < 1:", 1 < 2 < 1)
print("1 < 2 > 3:", 1 < 2 > 3)
print("1 < 2 > 1:", 1 < 2 > 1)
Of course, all of the comparison operators can be used (do try to not sacrifice the code readability):
In [14]:
a = 1
b = 2
c = 2
d = 0
print("1 < 2 == 2 >= 0:", a < b == c >= d)
print("1 < 2 == 0 >= 2:", a < b == d >= c)
print("1 < 2 >= 2 > 0: ", a < b >= c > d)
print("1 <= 2 >= 2 > 0:", a <= b >= c > d)
However, be very careful in other languages: the form with more than one comparison will be accepted by almost all of them, but it will not work as one would expect (like it does in Python)! This affects C/C++, MATLAB, PHP, PERL, Java, JavaScript,... It does work as expected in Mathematica. In R, it won't work at all (but at least it will report an error).
In [15]:
print("False == 0:", False == 0)
print(" type(False):", type(False))
print(" type(0):", type(0))
print(" type(False) == type(0):", type(False) == type(0))
print("True == 1:", True == 1)
print(" type(True):", type(True))
print(" type(1):", type(1))
print(" type(True) == type(1):", type(True) == type(1))
print("True != 2:", True != 2)
print(" type(True):", type(True))
print(" type(2):", type(2))
print(" type(True) == type(2):", type(True) == type(2))
Some languages (like PHP and JavaScript) have a strict equality operator ===
and strict inequality operator !==
that check both types and values of the compared objects. However, Python doesn't have that.
A conditional is created with if
statement and it is very similar to while
-loops, with the main difference being that its block will be executed at most once (if the condition is true).
Since the execution of the body is not repeated by the if
statement, there are two possible branches:
However, sometimes, we want to say
If
condition1
is true, dojob1
, else ifcondition2
is true, dojob2
, else dojob3
Here is an example of all three of these:
In [16]:
n = int(input("Input an integer: "))
if n < 0:
print("Number", n, "is negative.")
elif n > 0:
print("Number", n, "is positive.")
else:
print("Number", n, "has an identity crisis!")
Notice how else if
is abbreviated to elif
. This is to avoid too much indentation. Without it, we'd have to write:
In [17]:
n = int(input("Input an integer: "))
if n < 0:
print("Number", n, "is negative.")
else:
if n > 0:
print("Number", n, "is positive.")
else:
print("Number", n, "is a rebel!")
As before, all the controlling parts of a conditional (if condition
, elif condition
, and else
) need to end with a colon!
Of course, we can stack as many elif
parts as we need (including none of them), and we can ommit the else
part if we don't need it.
else
with loopsIn Python 3, it is possible to use else
in conjuction with loops. However, it is an unusual construct that other languages do not use and is best avoided by the new programmers. At this point, we haven't covered enough of Python to explain what it does.
So, be careful not to write
while condition1:
if condition2:
some_code
else:
some_code
instead of
while condition1:
if condition2:
some_code
else:
some_code
as Python will not report an error. It will instead do something, but not what you wanted.
We shall cover loops' else
statement later on in the course.
In [18]:
# We load some values, so we can test the code
a = float(input("a = "))
b = float(input("b = "))
# The solution to the problem
if a < b:
min_value = a
max_value = b
else:
min_value = b
max_value = a
# Print the result, to check if it's correct
print("a = ", a)
print("b = ", b)
print("Min:", min_value)
print("Max:", max_value)
Since Python has functions min
and max
, we can do this in a more Pythonic way:
In [19]:
# We load some values, so we can test the code
a = float(input("a = "))
b = float(input("b = "))
# The solution to the problem
min_value = min(a, b)
max_value = max(a, b)
# Print the result, to check if it's correct
print("a = ", a)
print("b = ", b)
print("Min:", min_value)
print("Max:", max_value)
This is wrong:
In [20]:
a = float(input("a = "))
b = float(input("b = "))
if a > b:
# a and b are in a wrong order, so we swap their values
a = b
b = a
# Print the result, to check if it's correct
print("Loaded:")
print(" a =", a)
print(" b =", b)
This is correct:
In [21]:
a = float(input("a = "))
b = float(input("b = "))
if a > b:
# a and b are in a wrong order, so we swap their values
tmp = a
a = b
b = tmp
# Print the result, to check if it's correct
print("Loaded:")
print(" a =", a)
print(" b =", b)
A Pythonic solution would be:
In [22]:
a = float(input("a = "))
b = float(input("b = "))
if a > b:
# a and b are in a wrong order, so we swap their values
(a, b) = (b, a)
# Print the result, to check if it's correct
print("Loaded:")
print(" a =", a)
print(" b =", b)
Please, do not use this until you know how and why it works.
How do we find digits of a number x
?
The last one is easy: x % 10
is the remainder of the division $x / 10$. But what about the rest?
Here is a simple trick: once we're done with the last digit, we don't need it anymore and we can discard it. How do we do that?
Hint: we have just used the %
operator to get the last digit. Is there an operator that gives x
without the last digit?
Of course there is: operator //
(integer division) is complementary to %
. More precisely, x // 10
gives us x
without the last digit.
In [23]:
x = int(input())
print("x =", x)
print("x % 10 =", x % 10)
print("x // 10 =", x // 10)
A word of warning: try the above code with a negative x
!
How do we deal with that?
There is a nice function for getting the absolute value of a number, conveniently called abs()
:
In [24]:
x = abs(int(input()))
print("x =", x)
print("x % 10 =", x % 10)
print("x // 10 =", x // 10)
So, here is a sketch of how to solve the above problem (sum of digits):
s = 0
,x
,x
and add it to s
,x
,x
has no more digits (i.e., it drops to zero).We'll add additional print()
to the loop, to follow the states of the variables.
In [25]:
s = 0
x = abs(int(input()))
print("x =", x)
while x > 0:
s += x % 10
x //= 10
print("sum = " + str(s) + "; x =", x)
print("final sum =", s)
print("final x =", x)
Important: Notice the final value of x
in the last line -- it is zero. Doing the above, the value of the variable is lost and cannot be recreated!
If we need the value of x
afterwards, we have to keep it in another variable (or do the whole thing in a function, as we shall soon see):
In [26]:
s = 0
x = abs(int(input()))
tmp = x
print("x = " + str(x) + "; s = " + str(s) + "; tmp = " + str(tmp))
while tmp > 0:
s += tmp % 10
tmp //= 10
print("x = " + str(x) + "; s = " + str(s) + "; tmp = " + str(tmp))
print("Final values: x = " + str(x) + "; s = " + str(s) + "; tmp = " + str(tmp))
By the way, there is a shorter way to do this, but specific to Python:
In [27]:
print(sum(int(d) for d in str(abs(int(input())))))
We'll be able to understand the above code later on.
Whenever we write
if some_condition:
do_something()
we are effectively saying
If
some_condition
is true, thendo_something()
.
This is pretty straighforward when some_condition
has a Boolean value. But, one can use most of the types in a condition. In this case, we say that we are using those values in a Boolean context.
Some general rules of evaluation in Boolean context:
None
and 0 (zero) evaluate to False
.
Non-zero numbers evaluate to True
.
Some examples:
In [28]:
x = 0
y = 1-1
if 0:
print("0 is true.")
else:
print("0 is false.")
if 17:
print("17 is true.")
else:
print("17 is false.")
if x:
print("x is true.")
else:
print("x is false.")
if y:
print("y is true.")
else:
print("y is false.")
if 1-1:
print("1-1 is true.")
else:
print("1-1 is false.")
As we learn new data structures, we will mention their Boolean interpretations as well. However, a general rule is: if it resembles a zero or if it is empty, its Boolean interpretation is False
; otherwise, it is True
. Still, if unsure, check for yourself:
In [29]:
print(bool(1))