Expressions and arithmetic operators

Published

2023-07-31

Expressions

In programming—and computer science in general—an expression is something which can be evaluated—that is, a syntactically valid combination of constants, variables, functions, and operators which yields a value.

Let’s try out a few expressions with the Python shell.

Literals and types revisited

The simplest possible expression is a single literal.

>>> 1
1

What just happened? We typed a simple expression—a single literal—and Python replied with its value. Literals are special in that they evaluate to themselves!

Here’s another:

>>> 'Hello, Python!'
'Hello, Python!'

Once again, we’ve provided a single literal, and again, Python has replied with its value.

You may notice that 'Hello, Python!' is rather different from 1. You might say these are literals of different types—and you’d be correct! Literals come in different types. Here are four different literals of four different types.

'Hello, Python' string (str)
1 integer (int)
3.141592 floating-point (float)
True Boolean (bool)

'Hello, Python!' is a string literal. The quotation marks delimit the string. They let Python know that what’s between them is to be interpreted as a string, but they are not part of the string itself. Python allows single-quoted or double-quoted strings, so "Hello, Python!" and 'Hello, Python!' are both syntactically correct. Note that if you start with a single quote (’), you must end with a single quote. Likewise, if you start with a double quote (“), you must end with a double quote.

1 is different. It is an integer literal. Notice that there are no quotation marks around it.

Given all this, the latter two examples work as you’d expect.

>>> 3.141592
3.141592
>>> True
True

What types are these? 3.141592 is a floating point literal (that’s a number that has something to the right of the decimal point). True is what’s called a Boolean literal. Notice there are no quotation marks around it and the first letter is capitalized. True and False are the only two Boolean literals.

Expressions with arithmetic operators

Let’s try some more complex expressions. In order to construct more complex expressions we’ll use some simple arithmetic operators, specifically some binary infix operators. These should be very familiar. A binary operator is one which operates on two operands. The term infix means that we put the operator between the operands.

>>> 1 + 2
3

Surprised? Probably not. But let’s consider what just happened anyway.

At the prompt, we typed 1 + 2 and Python responded with 3. 1 and 2 are integer literals, and + is the operator for addition. 1 and 2 are the operands, and + is the operator. This combination 1 + 2 is a syntactically valid Python expression which evaluates to… you guessed it, 3.

Some infix arithmetic operators in Python are:

+ addition
- subtraction
* multiplication (notice we use * and not x)
/ division
// integer or “floor” division
% remainder or “modulo”
** exponentiation

There are other operators, but these will suffice for now. Here we’ll present examples of the first four, and we’ll present the others later—floor division, modulo, and exponentiation. Let’s try a few (I encourage you follow along and try these out in the Python shell as we go).

>>> 40 + 2
42
>>> 3 * 5
15
>>> 5 - 1
4
>>> 30 / 3
10.0

Notice that in the last case, when performing division, Python returns a floating-point number and not an integer (Python does support what’s called integer division or floor division, but we’ll get to that later). So even if we have two integer operands, division yields a floating-point number.

What do you think would be the result if we were to add the following?

>>> 1 + 1.0

In a case like this, Python performs implicit type conversion, essentially promoting 1 to 1.0 so it can add like types. Accordingly, the result is:

>>> 1 + 1.0
2.0

Python will perform similar type conversions in similar contexts:

>>> 2 - 1.0
1.0
>>> 3 * 5.0
15.0

Precedence of operators

No doubt you’ve learned about precedence of operations, and Python respects these rules.

>>> 40 + 2 * 3
46
>>> 3 * 5 - 1
14
>>> 30 - 18 / 3
24.0

Multiplication and division have higher precedence than addition and subtraction. We also say multiplication and division bind more strongly than addition and subtraction—this is just a different way of saying the same thing.

As you might expect, we can use parentheses to group expressions. We do this to group operations of lower precedence—either in order to perform the desired calculation, or to disambiguate or make our code easier to read, or both.

>>> 40 + (2 * 3)
46
>>> 3 * (5 - 1)
12
>>> (30 - 18) / 3
4.0

So what happens here? The portions within the parentheses are evaluated first, and then Python performs the remaining operation.

We can construct expressions of arbitrary complexity using these arithmetic operators and parentheses.

>>> (1 + 1) * (1 + 1 + 1) - 1
5

Python also has unary operators. These are operators with a single operand. For example, we negate a number by prefixing -.

>>> -1
-1
>>> -1 + 3
2
>>> 1 + -3
-2

We can also negate expressions within parentheses.

>>> -(3 * 5)
-15

Summary of operator precedence

** exponentiation
+, - unary positive or negative (+x, -x)
*, /, //, % multiplication, and various forms of division
+, - addition and subtraction (x - y, x + y)

Expressions grouped within parentheses are evaluated first, so the rule you might have learned in high school and its associated mnemonic—PEMDAS (parentheses, exponentiation, multiplication and division, addition and subtraction)—apply.

Comprehension check

  1. When evaluating expressions, do you think Python proceeds left-to-right or right-to-left? Can you think of an experiment you might perform to test your hypothesis? Write down an expression that might provide some evidence.

  2. Why do you think 1 / 1 evaluates to 1.0 (a float) and not just 1 (an integer)?

More on operations

So far, we’ve seen some simple expressions involving literals, operators, and parentheses. We’ve also seen examples of a few types: integers, floating-point numbers (“floats” for short), strings, and Booleans.

We’ve seen that we can perform arithmetic operations on numeric types (integers and floats).

The operators + and * applied to strings

Certain arithmetic operators behave differently when their operands are strings. For example,

>>> 'Hello' + ', ' + 'World!'
'Hello, World!'

This is an example of operator overloading, which is just a fancy way of saying that an operator behaves differently in different contexts. In this context, with strings as operands, + doesn’t perform addition, but instead performs concatenation. Concatenation is the joining of two or more strings, like the coupling of railroad cars.

We can also use the multiplication operator * with strings. In the context of strings, this operator concatenates multiple copies of a string together.

>>> 'Foo' * 1
'Foo'
>>> 'Foo' * 2
'FooFoo'
>>> 'Foo' * 3
'FooFooFoo'

What do you think would be the result of the following?

>>> 'Foo' * 0

This gives us '' which is called the empty string and is the result of concatenating zero copies of 'Foo' together. Notice that the result is still a string, albeit an empty one.

Augmented assignment operators

As a shorthand, Python provides what are called augmented assignment operators. Here are some (but not all):

augmented assignment similar to
a += b a = a + b
a -= b a = a - b
a *= b a = a * b

A common example is incrementing or decrementing by one.

>>> a = 0
>>> a += 1
>>> a 
1
>>> a += 1
>>> a
2
>>> a -= 1
>>> a
1
>>> a -= 1
>>> a
0

You can use these or not, depending on your own preference.1

Original author: Clayton Cafiero < [given name] DOT [surname] AT uvm DOT edu >

No generative AI was used in producing this material. This was written the old-fashioned way.

This material is for free use under either the GNU Free Documentation License or the Creative Commons Attribution-ShareAlike 3.0 United States License (take your pick).

Footnotes

  1. The table above says “similar to” because, for example, a += b isn’t exactly the same as a = a + b. In augmented assignment, the left-hand side is evaluated before the right-hand side, then the right-hand side is evaluated and the result is assigned to the variable on the left-hand side. There are some other minor differences.↩︎