Types and Operations
replit
This was written prior to replit being placed behind making an account. I am unenthused with a cursory glance at alternatives, so I can't just substitute in another tool.
For this lecture, it will be convenient to have replit open.
replit is quite cool. On the left-hand side,
you can type python code and run it with the big, green "Run" button.
Go ahead and try it with print("Hello, World")
.
But we will be using the right-hand side today. On the right hand side you can put code/expressions (e.g. arithmetic) one line at a time. These will be evaluated, and the results will be displayed.
The distinction is subtle. It may by more useful to think of the right-hand side a "python calculator" of sorts.
Throughout this lecture,
whenever I show a block of code I run in replit (or any other "REPL"),
I will have a >>>
before the line of code, and the result on the following lines.
For instance:
>>> 123 + 456
579
Represents me running the line 123 + 456
in replit and seeing that
evaluate to the result 579
.
Note that in the runnable code blocks on the website
(which are more like running a python file),
I would need to print the result if I wanted to see it (print(123 + 456)
).
In replit, you are told the result.
Extra: REPLs
This calculator-like thing is more formally know as a read-eval-print loop (REPL), hence the name replit.
It reads an expression from the user, evaluates it, prints the result, and repeats (loops).
Extra: Python's built-in REPL
replit's python REPL is presumably a wrapper around python's built-in REPL.
If you are in a terminal (such as Terminal on Mac of PowerShell on Windows)
and python 3 is installed,
then you can start up the built-in REPL with the command python3
(if you have installed python, it is almost surely python 3).
That's it, just python3
with no file name after it.
To get out of the REPL, you can use the exit()
or quit()
function,
or you can hit control-d (it might be something else on Windows).
Types
We as humans understand the difference between numbers and words. Even within numbers, we have whole numbers, fractions, and decimals.
Computers formalise this with a notion of types. All data has some type associated with it. Everything is something, maybe a number, maybe text, and later on, maybe weirder things.
There are 3 types we care about at the moment:
- Integers (
int
): these are the whole numbers of python, e.g.:0
,1
,6
,-7
. - Floating point numbers (
float
): these are the decimal numbers of python, e.g.:0.0
,-1.67
,4e23
. - Strings (
str
): these are the "text" type of python. e.g.:"Hello, World!"
.
When we want to make a string out of verbatim text in code,
we surround it with quotation marks so that the computer knows it is text, not code.
We may use pairs of "
or '
(the start and end quote must match, both "
or both '
).
Note, these are both straight quotes.
Curvy quotes like “
, ”
, ‘
, and ’
do not work.
Extra: Infinity and NaN
There are some special float
s to mention exist:
- Infinity (prints as
inf
): hard to deliberately make show up, but anything more than1.8e308
or so is too big and thus "infinite". Why that specific number is much longer story. - Negative Infinity (prints as
-inf
): Much likeinf
, but negative. - Not a Number (prints as
nan
): Sometimes when you do illegal math you get an error (such as dividing by 0). Sometimes, like with1.8e308 - 1.8e308
(inf
-inf
) you get "Not a Number"
print(2e308) # inf
print(-2e308) # -inf
print(2e308 - 2e308) # nan
Extra: Escape Sequences
Sometime, you want to something a little fancy in your strings. Maybe you want a tab, maybe a newline, or maybe you want a quotation mark.
To do these things, we need what are called escape sequences.
These are sequences of characters starting with a special escape character.
The escape character, \
(backslash) in python,
tells the computer that what comes next is not verbatim,
but rather a special sequence telling it to do something else.
So for a new line, you can use "\n"
, for tabs, "\t"
.
(The website's live python is a bit buggy with fancy whitespace,
so you should try this in a REPL yourself.)
>>> print("Escapable Whitespace:\n\tNewlines\n\tTabs")
Escapable Whitespace:
Newlines
Tabs
For quotation marks, you don't need to escape if the marks around the entire string
differ from what you are trying to display. E.g., "'"
and '"'
work how you might hope.
You do need an escape if they match though, e.g., "\""
and '\''
.
>>> print("The ' in a \"...\"-style string doesn't need quotes")
The ' in a "..."-style string doesn't need quotes
>>> print('Don\'t forget to escape apostrophes in a \'...\'-style string')
Don't forget to escape apostrophes in a '...'-style string
Finally, if you want a backslash itself to show up in a string, \\
.
>>> print("Some Escape Sequences:\n\tNewline: \\n\n\tTab: \\t\n\tQuote (\"): \\\"\n\tBackslash (\\): \\\\")
Some Escape Sequences:
Newline: \n
Tab: \t
Quote ("): \"
Backslash (\): \\
Learning Something's Type
If you want to know what something's type is, you can use the type()
function.
This takes in anything and returns its type. For example:
print(type(-127)) # <class 'int'>
print(type(3.1415)) # <class 'float'>
print(type("Hello!")) # <class 'str'>
Ignore the class
thing (its basically just the technical name for "type" in python).
Arithmetic Operations
We have a notion of expressions in the computer science world.
The formal definitions can be a tad complex, by they are effectively
things that evaluate to something.
For instance, the expression 7 + 3 * 2
evaluates to 13
.
You are hopefully familiar with operations (as in "order of operations")
in the math sense. If we have the expression 7 + 8
, we call 7
and 8
operands, and +
the operator.
The basic arithmetic operators in python:
+
: Addition-
: Subtraction*
: Multiplication/
: Division**
: Exponentiation
print(3 + 5) # 8
print(3 - 5) # -2
print(3 * 5) # 15
print(3 / 5) # 0.6
print(3 ** 5) # 243
There are two more arithmetic operators in python. They both have to do with the concept of whole number division with a remainder. So for instance, while you could say divided by is , you could also say divided by is with a remainder of (because ).
The first approach is captured in python by /
, the second with the following:
//
: Integer Division/Floor Divisions.17 // 5
would give3
, the whole number of times to operator on the right can be taken out of the operator on the left.%
: Modulo/Remainder.17 % 5
would give2
, what remains of the operator on the left after the operator on the right is taken out of it as many times as possible.
These both also work on float
s in python.
print(17 // 5) # 3
print(17 % 5) # 2
print(18.5 // 5.1) # 3.0
print(18.5 % 5.1) # 3.2
(As a bonus,
you can even see the imperfection in the float
's ability to represent 3.2.)
Extra: ^
is not Exponentiation
You may have the instinct to represent as 3 ^ 5
,
though in python is actually represented as 3 ** 5
.
While this is wrong, it isn't syntactically illegal,
which can make it even trickier to catch as an error.
The following is far outside the scope of what we need to worry about in this class.
^
is an operator that only makes sense in the context of the underlying
binary representations of numbers.
Brief binary primer:
In "base 10" (our usual number system), we have a s, s, s, etc. place. These are "how many s, how many s, how many s, etc. And for each place, we can have between and (10 possibilities) of that particular .
In binary (or "base 2"), the places are for s. Each place can have or (2 possibilities) of that particular . For example:
- (or
0b11
in python) has a in the s (aka s) place, and a in the s (aka s) place. . - (or
0b101
in python) has a in the s (aka s) place, a in the s (aka s) place, and a in the s (aka s) place. .
So with the notion of binary representations in mind, there are some specific binary arithmetic operators:
&
: bitwise and. For each , the s place ofa & b
is a if both the s place ofa
is a and the s place ofb
is a ; otherwise it is a .|
: bitwise or. For each , the s place ofa | b
is a if either the s place ofa
is a or the s place ofb
is a (this includes if both are ); otherwise it is a .^
: bitwise exclusive or (xor). For each , the s place ofa ^ b
is a if exactly one of the s places ofa
andb
is (and the the other's is ); otherwise (both s or both s), it is a .
print(0b11) # 3 (0b011)
print(0b101) # 5 (0b101)
print(3 & 5) # 1 (0b001)
print(3 | 5) # 7 (0b111)
print(3 ^ 5) # 6 (0b110)
Order of Operations
With any luck, the phrase "order of operation" or "PEMDAS" is ingrained deep in your memory. If not, the idea is that in longer arithmetic expressions, some operations are done before others.
The order:
()
: Expressions in Parentheses have highest priority.**
: Exponentiation is the tightest binding operator.*
,/
,//
,%
: Multiplication, Division, and the like come next.+
,-
: Addition and Subtraction are last.
Some examples of results by using parentheses to change the order of evaluation:
print(5 ** 4 * 3 + 2) # 1877
print(5 ** 4 * (3 + 2)) # 3125
print(5 ** (4 * 3) + 2) # 244140627
print(5 ** (4 * 3 + 2)) # 6103515625
print(5 ** (4 * (3 + 2))) # 95367431640625
And within a level of precedence, the order of evaluation generally goes from left to right, both in math and in python. A demonstrated below:
print(2 - 3 + 4) # 3 (default left associativity)
print((2 - 3) + 4) # 3 (explicit left first)
print(2 - (3 + 4)) # -5 (explicit right first)
There is an interesting exception. Both in math and python, exponentiation goes from top/right to bottom/left. For example .
print(2 ** 3 ** 2) # 512 (default right associativity)
print((2 ** 3) ** 2) # 64 (explicit left first)
print(2 ** (3 ** 2)) # 512 (explicit right first)
Operands' and Result's Types
Since int
s and floats
are both numbers,
python lets you have operations with both in them:
>>> 2 * 3.1415
6.283
The type of the result depends on the type of the operands (and if the operation is division or not).
# print() can take multiple comma-separated arguments
print(1 + 1, type(1 + 1)) # 2 <class 'int'>
print(1 + 1.0, type(1 + 1.0)) # 2.0 <class 'float'>
print(1.0 + 1, type(1.0 + 1)) # 2.0 <class 'float'>
print(1.0 + 1.0, type(1.0 + 1.0)) # 2.0 <class 'float'>
print(1 / 1, type(1 / 1)) # 1.0 <class 'float'>
If either operand is a float
, or the operation is /
, the result will be a float
.
Otherwise (If both operands are both int
s and the operation is not /
), it will be an int
.
String Operations
We can work with more than numbers in python though. We also have text, aka strings (str
).
Turns out, there are some handy operations we can perform on strings:
+
: Concatenation. Combines 2 strings together.*
: Repeat. This takes, as operands, a string and an integer, in either order, and repeats the string that many times.
For example:
print("Hello" + " " + "World") # "Hello World"
print(5 * "ha") # "hahahahaha"
print("ho" * 3) # "hohoho"
Converting Types (Casting)
Finally, we can convert between these types if we so desire
(this is sometimes called casting).
For example, if we have the string "125"
, we may want to convert it to the
integer 125
.
Conversion function are conveniently named after their types:
int()
: attempts to convert something to anint
. E.g.,int("125")
evaluates to125
.float()
: attempts to convert something to afloat
E.g.,float("125")
evaluates to125.0
.str()
: attempts to convert something to astr
. E.g.,str(-0.12)
evaluates to"-0.12"
.
I say "attempts", because some things are illegal and will fail:
>>> int("3.14")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '3.14'
Finally, a warning about converting float
s to int
s,
the int()
function truncates (chops off) the decimal part.
You may find it more appropriate to use the round()
function.
print(int(126.9999999999)) # 126
print(round(126.9999999999)) # 127
Extra: Floor and Ceiling
This truncating, or rounding down, is also called flooring
(hence "floor division" from earlier, in fact).
It can also be deliberately done with math.floor()
in the
math
Module, explained more below.
The notion of rounding up is captured by the ceiling (math.ceil()
) function.
Extra: It's Technically not Conversion
This is material we will get to later.
For each type (technically class), there is a special function, who's name matches the name of the type (class), called a constructor.
Constructors construct an object of that type (class). They may also take in arguments to inform that construction.
So int(5.6)
isn't technically "converting" the float
5.6
to an int
,
but rather, creating a new int
based on the float
5.6
.
It's a subtle distinction, and for all intents are purposes is effectively conversion, but I like to include technically correct information where possible.
math
Module
If you want even more mathematical functions and features,
there is the math
module.
A module is effectively a collection of functions and/or constants that aren't included by default. The term library is also frequently used for this concept.
To load (or import or include) the math
module, use the command import math
(import <module_name>
for modules more broadly). You can use this command in the REPL.
There are useful function and constants in the module, like sqrt()
and pi
,
but in order to use them (at least with this import method), we must refer to them
as math.sqrt()
and math.pi
.
import math
print(math.sqrt(math.pi)) # 1.7724538509055159
A full list of the function available to in the math
module can be found
in the official documentation.