For example the Python programming language has undergone substantial syntactic evolution: print 4
became print(4)
. Those statements are syntactically different but semantically identical.
When implementing an algorithm, it is always tempting to jump right into the implementation, that is jump right to the syntax. I advocate you resist that impulse, and really think through your algorithm and the semantics of its implementation first (i.e., what building blocks will you use to construct your solution).
We will be using Python 3, a widely-used, widely-available, general-purpose programming language. Note that I said Python 3 (not 2), Python 3 is not backward compatible. Lets get started!
We will be using the Thonny integrated development environment (IDE).
Today we will be working in the bottom (or right) box, the “Shell”. This gives us access to Python’s REPL (read-eval-print-loop), also called an interpreter.
The >>>
is the prompt for us to enter Python code.
Let’s try some basic expressions, hitting enter after each:
>>> 1
1
>>> 5
5
These are “literal” expressions, because the resulting value is the same as the expression itself.
Now some more complex expressions that include “operators”:
>>> 2 + 2
4
>>> 15 * 20
300
>>> 20 / 4
5.0
>>> 10 - 20
-10
When we hit “enter”, Python is evaluating the expression (the “eval” in REPL) and printing the results.
What about errors?
>>> 2 asdf 2
File "<pyshell>", line 1
2 asdf 2
^
SyntaxError: invalid syntax
We didn’t follow the syntactic rules of the language and so Python reported an error. Python has no idea what “asdf” means, it is not an operator built-in to the language.
Helpfully, Python does tell us where it encountered the error (which may or may not be the same as location of the cause of the error), but it doesn’t tell us how to fix it (because it can’t read our minds to know what we wanted it to do). Often the error messages will seem a little opaque, one of the skills you will develop over time is the mapping of error messages to the actual error itself.
Earlier we saw 5
and 5.0
. What is the difference? They have different
types. 5.0
is a floating point value or float, 5
is an integer value or int.
A type consists of two things:
Integers are exactly what they sound like, while floating point numbers are a subset of the Real numbers. Both are necessarily finite subsets of their domains, that is the computer can’t represent all real numbers at infinite precision. Note, we will learn much more about numerical precision at the end of the semester.
Let’s investigate an example of “set of operations” by figuring out the difference between ‘/’ and ‘//’. Both are valid Python operators.
>>> 8 / 3
2.6666666666666665
>>> 8 // 3
2
What do you notice? The latter appears to round to an integer. How does it round? It doesn’t appear to be “normal” rounding rules (since 2.66 ≥ 2.5 it should have rounded to 3), but is it rounding “down” or rounding towards zero? How could we figure out?
>>> -8 // 3
-3
The above shows us it always rounds “down” (towards negative infinity). And in fact this is called the “floor division” operator. What are the type rules for these operators and how are they different? We can already see integer division and integer floor division produce different types. How could we figure out the type rules? Much as we did above we could experiment…
>>> 8 / 3.0
2.6666666666666665
>>> 8 // 3.0
2.0
>>> 8.0 // 3
2.0
...
What we observe is that division of integers produces a float, while floor division of integers produces an integer. For both operators, if either operand is a float, the other is converted to a float (if not already) and the result is a float. Note that ‘//’ applied to floats still rounds “down”.
This experimentation is not at the exclusion of reviewing the documentation. In general, we should start by consulting the relevant Python documentation (which in this case confirms and expands upon our observations). However, we want to develop both skills: 1) using the documentation and 2) infer/verify behavior via experimentation
What about more complex expressions involving multiple operators, e.g., 2 + 3 * 4
? In general, Python follows PEMDAS. So this expression would be interpreted as 2 + (3 * 4)
and evaluate to 14, i.e.,
>>> 2 + 3 * 4
14
PI questions (don’t use the interpreter, we are trying to build up our intuition)
Let’s think about non-numeric types
>>> "hello"
'hello'
We term "hello"
a string literal because it is a string (sequence) of
characters whose value is the characters themselves, i.e., we are literally and
exactly specifying the value. We indicate strings by characters between either
double or single quotes (you can’t mix double and single quotes). Thus
"hello"
and 'hello'
are equivalent.
We can apply certain operators to strings, for example
>>> "hello" + "goodbye"
'hellogoodbye'
>>> "hello" * 2
'hellohello'
but what about:
>>> "hello" + 2
Traceback (most recent call last):
File "<pyshell>", line 1, in <module>
TypeError: must be str, not int
Python is telling us that adding an integer to a string isn’t a supported
operation of string types. Concatenation of strings with +
is supported (we
just saw that) and Python does know how to convert integers to strings. But
Python won’t do so implicitly as it can’t be sure that is what you intended (recall what we learned previously about ambiguity). You need to explicitly convert the integer to a string with the str
function (As you might expect, there are corresponding int
and float
functions that convert the input to the corresponding types - including strings. Try int("10")
in the shell).
>>> "hello" + str(2)
'hello2'
Everything we have done so far was very ephemeral. We gain tremendous power by being able to save and use intermediate results.
Assignment syntax: <variable> = <expression>
Example:
>>> x = 7
Nothing was printed by the REPL. So did anything happen? To figure it out, lets build up our mental model of what is going on in the Python interpreter.
Assignment semantics:
Python Tutor Memory Model Picture
Unlike expressions, the assignment statement does not evaluate to a value (that is printed to the REPL).
PI questions (don’t use the interpreter, we are trying to build up our intuition) (credit)
Python variable names can generally be of any length, contain upper and lower case letters, digits and the underscore character (_
). Although variable names can contain digits, a variable name can’t start with a digit. Additionally there are a set of Python keywords (or “reserved” words) such as def
that have specific meaning in the Python language and so can’t be used as variable names. As you might imagine variable naming can get very contentious. We will talk a lot more about good “style”, of which variable naming is an important aspect, but in the meantime, aim for concise, descriptive variables names (e.g. “income” instead of “i” of “asdf”) that minimize the cognitive burden anyone reading your code.
If we close and restart Thonny and try to use variables we created last time, we will get errors
>>> x
Traceback (most recent call last):
File "<pyshell>", line 1, in <module>
NameError: name 'x' is not defined
We could repeat everything that we did, e.g.
>>> x = 4
>>> x
4
but that is very inefficient and can’t possibly be the “way”,
If we want to save our code, and use that code to regenerate results, we will need to create additional files. We can do so using the text editor panel in Thonny.
# An example script
x = 7
x
Everything to the right of ‘#’ (and including the ‘#’) is a comment and is not executed. It is an explanatory note for the reader (which will often be you!).
I will create a script with our command, save the file, and then run it (with the green arrow).
The result is the similar to if we had typed the same code into the
interpreter, except we don’t get line-by-line feedback. That is we are not
executing each line in the context of REPL (with the “print”) but just “read” and
“eval”. We will need to use explicit print
functions to see the result.
# An example script
x = 7
print(x)
But we can use the variables we defined in the file later in the interpreter:
>>> x
7
Lets introduce an error so we see what Thonny reports, e.g. referencing an
undefined variable y
:
>>> %Run lecture2.py
Traceback (most recent call last):
File "lecture2.py", line 3, in <module>
y
NameError: name 'y' is not defined
PI questions (don’t use the interpreter, we are trying to build up our intuition)