How to Make Choices

Operators, Expressions and Statements

An expression is a combination of identifiers, values and operators which computes a value. It is quite similar to an arithmetic expression, with the only difference that the scope of programming languages expressions is way bigger since they can compute any kind of data, be they numerical or otherwise. We have already delved into identifiers and values; what we miss to write proper Python expressions are now the operators. They are special symbols and keywords that instruct a computation between two values. The semantics of an operator depends on the type of its operands.

Logical Operators (Yield Boolean)

Logical operators allow to manipulate and chain boolean values. Non-boolean values can also be operands of a logical operator, but they will be implicitly converted to boolean values with the bool() data type constructor before evaluation.

not (unary negation) is used to change the state of a boolean type, from False to True, from True to False. It is like pressing a switch. "Unary" means that the operator only affects the following operand.

or is used to build a logical expression that will evaluate True if any of the operands is True. Look at the diagram: the pipe has a fork with a tap on each side. The fork is the "or" operator, and the taps are the operands; if any of the valves are open (True), the water will flow on the other side.

and (conditional and) is used to build a logical expression that will evaluate True if every operand is True. Look at the diagram: a straight pipe represents the boolean expression with two taps following each other. The only way to let the water through is to open both valves. Meaning that every operand has to be True.

and and or are also referred to as "short-circuit" operators, because the interpreter will not evaluate the entire expression if unnecessary.

Here is a table showing their behaviours:

Expression

Output

not True

False

not False

True

True and True

True

False and True

False

False and False

False

True or True

True

True or False

True

False or False

False

Take into account that logical operators accept any type as operands, not only Boolean. If the operand type is non-boolean, the interpreter will convert the expression to a Boolean value and only after that evaluate the logical expression. For example:

First step

Second step

Third step

Result

0 and 5

bool(0) and bool(5)

False and True

False

1.0 or 2.5

bool(1.0) or bool(2.5)

True or True

True

not 0

not bool(0)

not False

True

not 2

not bool(2)

not True

False

and so on. Check the Boolean Type section if you have any doubt concerning the way bool() works.

Equality Operators (Yield Boolean)

To make reasonable choices, evaluating if values are the same is very important. Python can test two different notions of “sameness”, equality and identity:

Operators

Meaning

is

same identity

is not

different identity

==

equivalent

!=

not equivalent

It is essential to understand the difference between the two different notions in order to write reliable and semantic code.

Equality operators investigate the values of the objects referred; they are usually integers, strings, containers:

Identity operators instead, check if two identifiers refer or not to the same object. So, in different words, they check if two identifiers are pointing to the same place in memory. Let’s write a little variation of the code above:

So, when should you use what? When comparing numbers, text, containers content is good practice to use == and !=. Avoid is and is not, they are ambiguous and often not reliable because of caching. Instead, when comparing identifiers to singletons (True, False, None) you should always use is and is not. Why? Because there is only one instance of each of these type (therefore their identity is reliable) and makes your code more readable.

if isDark is True:
turnLight()

Comparison Operators (Yield Boolean)

Sorting things is quite a big deal in programming. Python provides a few operators able to detect the size of two expressions:

When comparing non-integer instances, they are translated in a numerical value and then evaluated. For example, strings are converted to sequences of integers according to the position of each character into the Unicode standard.

Arithmetic Operators (Yield Floating Point or Integer)

Computers have the ability to compute arithmetical expression very quickly. Python, of course, supports the standard arithmetic operators as follows:

Operator

Operation

+

addition

-

subtraction

*

multiplication

/

division

//

integer division

%

modulo operator

**

power of

Addition, subtraction and multiplication have a very straightforward behaviour: if both operands are integer, they yield an integer. If one of the operands is a floating point, they will return a floating point value. For example:

2 + 3.5 # 5.5
2-1 # 1
10*3 # 30

Division has two different operators which behave slightly differently. The standard division is what you would expect from it:

6 / 4 # 1.5

If you are allowed to slice units,
you can proceed as follows:

The integer division instead yields the mathematical floor of the quotient:

6//4 # 1

if you can’t slice units you group 4 units only once from a collection of 6

The modulo operator yields the remainder of such division:

6 % 4 # 2

In combination with the equivalent (==) or not equivalent (!=) operator, the modulo can be really helpful in checking whether a number is even or odd, whether a number is decimal or not and so on

Compound Expressions

Python provides the opportunity to combine more expressions at once. The result of these compound expressions relies on the evaluation of each single expression within it. The order of evaluation affects the final result, so it is very important to get a grip on precedence standard of the interpreter. For example:

5+2*8 # 21

Because of the higher precedence of multiplication over addition, 2*8 is evaluated first, then 16 is added to 5, giving 21 as result. In order to manipulate the execution order of evaluation, parenthesis can be used. For example:

(5+2)*8 # 56

Here is a concise table of the expressions evaluation order sorted by higher precedence

Expressions

Operators

function call, slicing sequence

func(), sequence[]

exponentiation

**

multiplication, division

*, /, //, %

addition, subtraction

+, -

comparisons

is, is not, ==, !=, , >=

logical not

not

logical and

and

logical or

or

assignments

=, +=, -=, /=, *=

Colon Syntax

As we already mentioned, whitespace is semantic in Python. This means that in order to group lines of code it is necessary to compose the statements which form the block accordingly. Consider the following list of words:

potatoes
groceries
eggplants
tomatoes

Here we are taking no advantage of visual variables in order to make the hierarchy more accessible to readers. We can only rely on the meaning of these words and try to detect a possible structure. So, at first sight, we detect no hierarchy, but after reading, we notice that groceries can group all the other items.

There are a few contrivances we can implement to express this structure at best using only typography. Let’s start to make some order moving groceries to the top:

groceries
potatoes
eggplants
tomatoes

Then we should find a way to associate unequivocally potatoes, eggplants and tomatoes as part of the same group. A very elegant and economic way is to move their alignment rightwards, like this:

groceries
potatoes
eggplants
tomatoes

After grouping, hierarchy. A very common and shared way of tag the first line of a list as a title is to use the colon sign, like:

groceries:
potatoes
eggplants
tomatoes

If we compare the final outcome with the original one, we will notice a sensible improvement. We do this all day without even noticing. We activate visual variables in order to build images with clear meanings that are easy to access to other people. It is a subtle kind of grammar, but an extremely powerful one.

The designer of Python, Guido van Rossum, decided to implement such behaviour into the Python programming language. This behaviour is mandatory, meaning that the Python interpreter expects the user to indent code semantically in order to organize code blocks.
These statements need a colon as final delimiter:

if, elif, else
for
while
with
def
try, except, finally
class

The code related to the statement needs to be indented four spaces rightwards – tab is also accepted by the interpreter but not recommended – in order to be considered as the body of the construct. For example:

if index != 0:
print('something')
print('something else')

‘something else’ is not part of the conditional construct because it falls out of the indented body. Consider also that Python allows nested structures like:

for eachElem in iterable:
if eachElem == target:
print 'found!'

In order to execute the conditional construct nested into the for-loop, this has to be indented four spaces more than its parent statement, which is already indented four spaces. Meaning, it has to be indented eight spaces rightwards. Just like a matryoshka.

Conditional Execution

Now that we have the tools, we need to instruct the interpreter to make reasonable choices. As we already said, it is critical while programming to be able to check whether a condition is true or not and then to be able to reroute the execution flow on different blocks of code.

Here’s a common standard diagram used to describe these patterns is the flowchart:

Python provides a control structure called “conditional construct” which allows to define whether a block of code should be executed or not. The minimal form of a conditional structure is:

if condition:
body

Here’s a concrete example:

newPage(100, 100)
myVar = 10
if myVar < 20:
rect(10, 10, 40, 40)

The condition is a Boolean expression. If this expression results in a True value, the indented block of code that follows will be executed. The body of the conditional construct can include other nested structures, they only need to be indented accordingly.

In this case, whether the body is executed or not, a rectangle will be drawn on the canvas.

An else statement can be placed at the end of the conditional construct. The instructions grouped into this statement will be executed if any other statement (if, elif) of the conditional construct is not met. Here’s how it is used:

Take note of the use of indentation. if, elif and else are aligned to the left while their bodies are four spaces indented to the right.

Workbook

Create a 200x200pt canvas. Draw a sequence of squares from top to bottom using a while loop. The square side should be adjustable through a variable. Odd squares should be light gray, even tiles should be dark gray.

Extend the previous exercise. Nest two while statements and draw a pattern made of squares across the entire canvas. Try to get a chessboard effect.

Write a program able to draw a ruler of a specific measure unit (either PostScript points or millimeters) across the entire canvas. The ruler ticks should be of different lengths according to a given rhythm. Use a while loop. Numbers displayed along the ruler are a plus.

Write a program able to draw a circle positioned at the center of the canvas. Its size should react to a parameter "factor" between 0 and 1:

if 0, the diameter should be a quarter of the canvas height

if 1, the diameter should be three-quarters of the canvas height

anything in between should smoothly interpolate
Define also a variable "switch" pointing to a boolean value. A True value should create a black circle on a white background, otherwise the opposite.