Skip to main content

Types and Operations

replit

note

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 floats to mention exist:

  • Infinity (prints as inf): hard to deliberately make show up, but anything more than 1.8e308 or so is too big and thus "infinite". Why that specific number is much longer story.
  • Negative Infinity (prints as -inf): Much like inf, 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 with 1.8e308 - 1.8e308 (inf - inf) you get "Not a Number"
Fun_Floats
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:

Get_Type
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
Arithmetic
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 1717 divided by 55 is 3.43.4, you could also say 1717 divided by 55 is 33 with a remainder of 22 (because 53+2=175 * 3 + 2 = 17).

The first approach is captured in python by /, the second with the following:

  • //: Integer Division/Floor Divisions. 17 // 5 would give 3, 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 give 2, 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 floats in python.

Division
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 353 ^ 5 as 3 ^ 5, though in python 353 ^ 5 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.

danger

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 11s, 1010s, 100100s, etc. place. These are "how many 10010^0s, how many 10110^1s, how many 10210^2s, etc. And for each place, we can have between 00 and 99 (10 possibilities) of that particular 10n10^n.

In binary (or "base 2"), the places are for 2n2^ns. Each place can have 00 or 11 (2 possibilities) of that particular 2n2^n. For example:

  • 11211_2 (or 0b11 in python) has a 11 in the 202^0s (aka 11s) place, and a 11 in the 212^1s (aka 22s) place. 112=121+120=311_2 = 1 * 2^1 + 1 * 2^0 = 3.
  • 1012101_2 (or 0b101 in python) has a 11 in the 202^0s (aka 11s) place, a 00 in the 212^1s (aka 22s) place, and a 11 in the 222^2s (aka 44s) place. 1012=122+021+120=5101_2 = 1 * 2^2+ 0 * 2^1 + 1 * 2^0 = 5.

So with the notion of binary representations in mind, there are some specific binary arithmetic operators:

  • &: bitwise and. For each nn, the 2n2^ns place of a & b is a 11 if both the 2n2^ns place of a is a 11 and the 2n2^ns place of b is a 11; otherwise it is a 00.
  • |: bitwise or. For each nn, the 2n2^ns place of a | b is a 11 if either the 2n2^ns place of a is a 11 or the 2n2^ns place of b is a 11 (this includes if both are 11); otherwise it is a 00.
  • ^: bitwise exclusive or (xor). For each nn, the 2n2^ns place of a ^ b is a 11 if exactly one of the 2n2^ns places of a and b is 11 (and the the other's is 00); otherwise (both 11s or both 00s), it is a 00.
Bit_Arithmetic
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:

Order_of_Operations
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:

Normal_Associativity
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 232=2(32)2 ^ {3 ^ 2} = 2 ^ {(3 ^ 2)}.

Exp_Associativity
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 ints 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).

Result_Type
# 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 ints 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:

String_Operations
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 an int. E.g., int("125") evaluates to 125.
  • float(): attempts to convert something to a float E.g., float("125") evaluates to 125.0.
  • str(): attempts to convert something to a str. 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 floats to ints, the int() function truncates (chops off) the decimal part. You may find it more appropriate to use the round() function.

Float_to_Int
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.

Math_Module
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.