# 2. Types

## 2.1. Variable

There is the fundmental concept of a `variable` in programming languages. Mathematically, a variable is a symbol denoting an unknown value. A most popular symbol denoting an unknown value in math is `x`. In computer programming, however, one useful mental model of a variable is to think of it as a `box`. In life, what can you do with a box?

• you can put something into a box

• you can take something out of a box

• you can label a box meaningfully

A variable is simply a storage container. Let’s not get too technical in understanding what is a variable, as going to such level is not necessary to knowing how to effectively create and use variables when programming.

Last thing before moving on, each variable as a `type` associated with it. The variable type is determined by what it is storing. If a variable (a box) is storing an integer number, then the variable is said to be an integer variable. If a variable is storing a car, then the variable is siad to be a car variable. Whatever the box is storing determines the type of the box.

## 2.2. Basic types

There are four basic or `primitive` types in Python. They are `float`, `integer`, `boolean` and `string`. You can remember these four types with the acronym, `FIBS` (float, integer, boolean, string). What are these types actually?

• an integer is a whole number value

• a float is a decimal number value

• a string is a text value

• a boolean is either true or false

A lesser known Python type is a `complex number` value. Below, we declare and initialize 5 variables, each storing one of the 5 basic variable types. Note the symbol `=`, which is called the `assignment operator`. To the left of the assignment operator is the variable name, and to the right is a literal value (e.g. string literal, integer literal, float literal, boolean literal and complex number literal). If you read the line `i = 32` naturally, you should read it as i is assigned to 32 and not i is equal to 32.

``` 1# a string
2s = 'Hello, world!'
3
4# a boolean
5b = True
6
7# an integer
8i = 32
9
10# a float
11f = 3.14
12
13# a complex number
14c = 2+3j
```

Note

In Python, boolean values are either `True` or `False`. Notice that these boolean literal values have the first letter capitalized? This convention is atypical, as other languages specify boolean values completely in lower case (e.g. `true` and `false`).

After you declare a variable and assign a value to it, you may print it to the terminal.

```1age = 32
2print(age)
```

The value `32` will be printed to the terminal, and not the variable name `age`. Remember we said to think of a variable as a box? You can put stuff in, take stuff out and label it meaningfully? Putting something into a box is accomplished through the assignment operator. Labelling the variable meaningfully is accomplished by giving a name that hints at the context. Taking something out of the box is accomplished through functions such as print; somehow, the print function is able to reach into the box and take what we have stored in it to be printed to the terminal.

Note

Said by Phil Karlton, “There are only two hard things in computer science: cache invalidation and naming things.” Do not underestimate how difficult it is to give meaningful names to variables. A variable name such as `x`, `y` or `z` does not indicate or hint at any context.

Warning

When giving names to variables in Python, there are some words that cannot be used since these words are themselves used as a part of the Python language’s syntax. Such words are called `keywords` and a few examples are as follows.

• for

• in

• set

• list

• tuple

• and

Another useful rule in naming variables is that variable names cannot have spaces. The convention in Python is that when you name a variable and there should be spaces, substitute underscores `_` for the spaces. For example, if we have a variable to store a first name, we should name that variable `first_name`.

Note

There are 3 main conventions to name variables across programming languages. The conventions arise from dealing with variable names that have multiple words. For example, if we have a variable to store a person’s last name, we can name the variable using Pascal casing, camel casing or snake casing (also called kebab casing).

```1LastName = 'Doe' # pascal casing, used in C#
2lastName = 'Doe' # camel casing, used in Java
3last_name = 'Doe' # snake casing, used in Python
```

In Python, snake casing is the convention to use in naming variables, although your code will still work if you use Pascal or camel casing.

### 2.2.1. Question

In the code below,

• what type is the variable `s`?

• what type is the variable `b`?

• what type is the variable `i`?

• what type is the variable `f`?

• what type is the variable `c`?

```1s = 'test'
2b = False
3i = 3
4f = 3.14
5c = 17 + 29j
```

Solution.

• `s` is a string variable

• `b` is a boolean variable

• `i` is an integer variable

• `f` is a float variable

• `c` is a complex number variable

### 2.2.2. Question

Create variables to store your name, age, height and whether you like pizza. Print the variables.

Solution.

```1name = 'John'
2age = 32
3height = 5.5
4pizza = True
5
6print(name)
7print(age)
8print(height)
9print(pizza)
```

### 2.2.3. Specifying a variable’s type

In Python, the variable type is inferred from what it is storing; we do not have to explicitly declare the variable type with the variable name. Python is said to be a `dynamically typed` language, as compared with other languages that are `statically typed` where when you declare the variable name, you must also declare the variable type. However, in later versions of Python, you may declare the variable type associated with the variable name as follows. (As programmers from other statically typed languages have begun to adopt Python, you will see more Python code that specify type information with variables.)

``` 1# a string
2s: str = 'Hello, world!'
3
4# a boolean
5b: bool = True
6
7# an integer
8i: int = 32
9
10# a float
11f: float = 3.14
12
13# a complex number
14c: complex = 2 + 3j
```

Note

There is a difference between dynamically- versus statically-typed languages and weakly- versus strongly-typed languages. Dynamically- and statically-typed languages refer to what types of values a variable can store after they are declared. For example, in Python, we can declare a variable and assign anything to it later without problem.

```1a = 'test'
2a = 3
3a = 3.4
```

In Java, once we declare a variable and its type, we cannot assign values to that variables that are not of the same type.

```1int a = 32;
2a = 42; // legal, since 42 is an int
3a = "test"; // illegal, cannot be done in Java
```

Weakly- versus strongly-typed languages refers to the ability to force values into unrelated types. Weakly-typed languages can force values into unrelated types (e.g. an integer to a string), while strongly-typed languages cannot. Python is a strongly-typed language and JavaScript is a weakly-typed language. For example, in Python, we cannot add or concatenate a string with an integer.

```1a = 1
2b = '1'
3
4# illegal in python, error will be thrown
5c = a + b
6
7# legal in python now, since a is forced into being a string
8d = str(a) + b
```

In JavaScript, we can add or concantentate a string with an integer.

```1const a = 1;
2const b = '1';
3const c = a + b; // legal in JavaScript, c is '11' as a is forced into being a string
```

Python is said to be a dynamically- and strongly-typed language. Java is said to be a statically- and strongly-typed language. JavaScript is said to be a dynamically- and weakly-typed language.

## 2.3. String

Let’s dive a bit deeper with strings.

### 2.3.1. String creation

Creating strings may be done with single, double or triple-quotes. Single and double quotes are the most common way to create strings in Python. Triple-quote strings are a bit special in that they enable you to define multi-line text.

``` 1# single quotes
2s = 'Hello, world!'
3
4# double quotes
5s = "Hello, world!"
6
7# triple quotes
8s = """This is some very long text.
9It uses triple quotes.
10"""
```

If you are using single quotes to create a string and your text has a single quote, you must escape the single quote with a backslash `\`. For example, `'I'm feeling happy and awesome today'`. Likewise, if you are using double quotes to create a string and your text has a double quote, you must escape the double quote with a backslash. For example, `"She said, "I love to code in Python.""`.

Anything enclosed with single (or double) quotes is considered a string. All the variables below are string variables since they are storing string literals. One might jump to the conclusion that `b` should be considered an integer variable, however, `b` is assigned to a string `b = '32'`; if we did `b = 32` (no single quotes), then `b` would be an integer variable.

```1a = 'car'
2b = '32'
3c = '3.14'
4d = 'True'
```

### 2.3.2. String concatenation and interpolation

Building strings in Python is rather fun and may be accomplished in a few different ways. You may build a string from other strings, a process called concatenation. You may create a string template and format that template with values. Or, lastly, you may use the new `f-string` approach. Below, we show different ways to build strings.

``` 1# concatenating strings
2s = 'Hello, ' + 'world!'
3
4# interpolating values into a string using place holder
5age = 32
6s = 'I am {} years old'.format(age)
7
8# interpolating values into a string using a named place holder
9s = 'I am {age} years old. She is also {age} years old.'.format(age=age)
10
11# using f-string
12s = f'I am {age} years old. She is also {age} years old.'
13
14# formatting floats in a string
15pi = 3.1415
16s = f'the value of pi is {pi:.2f}'
17
```

### 2.3.3. Exercise

Use a f-string to create a string with the following pieces of information about a person.

```1name = 'John'
2age = 55
3weight = 170.8
```

Solution.

```1s = f'{name} is {age} years old and weighs {weight} pounds.'
2print(s)
```

### 2.3.4. String manipulation

It’s pretty neat what we can do to strings in Python. If we want parts of a string, we can slice a string using the bracket and index notation `[:]`. Additionally, associated with every string are many utility methods such as ones to upper case and lower case a string. We show a few examples of string manipulations below.

``` 1s = 'Hello, world!'
2
3# get the first 5 characters
4a = s[0:5]
5
6# the the 7th to 12th characters
7b = s[7:12]
8
9# make string upper case
10c = s.upper()
11
12# make string lower case
13d = s.lower()
14
15# trim string of leading and trailing spaces
16s = ' Hello, world! '
17e = s.strip()
18
19# make a string title case
20s = 'where the red fern grows'.title()
```

### 2.3.5. Exercise

Assume we have a person’s first name and last name. Create a new string to store the initials of this person.

```1first_name = 'John'
2last_name = 'Doe'
```

Solution.

```1initial = f'{first_name[0]}.{last_name[0]}.'
2print(initial)
```

## 2.4. List

A list is a type of collection of items. The items in a list are called elements. If a variable may be thought of as a box, then a list may be thought of as a box of boxes.

Lists are defined using square brackets `[]`. Although a list can store mixed types of elements, avoid doing so; try to store values or variables of only one type in lists. If you store mixed variable types in a list, some operations, such as sorting, will not work out of the box as order comparison will break down (how do you compare if a string is less than an integer?).

``` 1# empty list
2months = []
3
4# list with pre-defined elements
5months = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
6
7# get element from list
8x = months[0]
9
10# slice a list
11x = months[0:5]
12
13# update element in list
14months[0] = -1
15
17months.append(11)
18
19# remove element in list
20months.remove(-1)
21
22# extend a list
23months.extend([11, 12])
24
25# concatenate two lists
26months = [0, 1, 2, 3, 4] + [5, 6, 7, 8, 9, 10]
27
28# get length of list
29x = len(months)
30
31# check if element is in list
32result = 1 in months
33
34# list of lists
35matrix = [[0, 1], [2, 3]]
```

### 2.4.1. Exercise

Let’s say you have the lists of favorite sports for two people, Jack and John, from most favorite to least favorite.

• How do you combine the lists?

• How do you sort the combined lists?

• How do you get Jack’s favorite sport?

• How do you get John’s least favorite sport?

```1jack = ['baseball', 'basketball', 'football']
2john = ['rugby', 'soccer', 'judo']
```

Solution.

``` 1# combine the list
2sports = jack + john
3
4# sort the combined list
5sports.sort()
6
7# jack's most favorite sport
8print(f'{jack[0]}')
9
10# john's least favorite sport
11print(f'{john[2]}')
```

## 2.5. Set

A set is also a type of collection of items. The difference between a list and a set is that a set does not allow for duplicate elements; only unique elements are allowed in sets. No matter how you try to insert duplicate elements into a set, the set will only have one copy of an element. Note that we use curly braces `{}` to create a set.

``` 1# empty set
2s = set()
3
4# declare with curly braces
5s = {1, 1, 2, 3}
6
7# create a set from a list
8s = set([1, 1, 2, 3])
9
12
13# remove item
14s.remove(4)
15
16# check if element is in set
174 in s
181 in s
19
20# set operations
21
22a = {0, 2, 4, 6}
23b = {1, 2, 3, 4}
24
25# uinion: {0, 1, 2, 3, 4, 6}
26union = a | b
27
28# intersection: {2, 4}
29intersection = a & b
30
31# difference: {0, 4, 6}
32diff = a - b
33
34# symmetric difference: {0, 1, 3, 6}
35symmetric_diff = a ^ b
```

When using sets, the ordering of elements is not guaranteed. If you run the following code, the ordering of the elements in the sets may change. If order is important, use a list or convert the set into a list. Sets are intended to be used for existence checks where ordering plays no role.

```1print({'john', 'mary', 'jack'}) # could print {'john', 'mary', 'jack'}
2print({'john', 'mary', 'jack'}) # could print {'mary', 'john', 'jack'}
3print({'john', 'mary', 'jack'}) # could print {'mary', 'jack', 'john'}
```

Note

It’s easy to convert between a set and a list.

```1s = {1, 1, 2, 3, 4}
2l = list(s) # convert the set to a list
3
4l = [1, 1, 2, 3, 4]
5s = set(l) # convert the list to a set
```

### 2.5.1. Exercise

Let’s say we have the set of toppings that Mary and Jane want to have on their pizzas.

• Which toppings does Mary like that Jane does not like?

• Which toppings does Jane like that Mary does not like?

• Which toppings do Mary and Jane both like?

• If we need to order a pizza with all the toppings they both like, what would be all the toppings?

```1mary = {'bacon', 'bell pepper', 'cheese'}
2jane = {'jalepanos', 'cheese', 'sausage'}
```

Solution.

``` 1# mary likes, jane does not like
2print(f'{mary - jane}')
3
4# jane likes, mary does not like
5print(f'{jane - mary}')
6
7# jane and mary like
8print(f'{jane & mary}')
9
10# all liked toppings
11print(f'{mary | jane}')
```

## 2.6. Map

A map is a collection of key-value pairs. A map is synonomously called a dictionary or an associative-array. The keys in a map must be unique, and the values in a map can be any data structure. Additionally, keys must be hashable, meaning, keys must be able to be represented (nearly) uniquely as integers. If something is not hashable, then it cannot be used as a key in a map. Typically, strings are the best types of data to use as keys in maps.

Note

Like sets, maps are declared and initialized using curly braces `{}`. Unlike sets, elements (or the key-value pairs) of a map must be specified using colon `:` e.g. `{'age': 32}`.

Like lists, values associated keys are accessed using square brackets `[]`. Unlike lists, the key must be used to access the corresponding value (instead of the index) e.g. `map['age']`.

``` 1# declare with dict
2m = dict()
3m['John'] = 18
4m['Jack'] = 19
5m['Jeremy'] = 17
6
7# declare inline
8m = {
9    'John': 18,
10    'Jack': 19,
11    'Jeremy': 17
12}
13
14# get value from map
15age = m['John']
16
17# update value in a map
18m['John'] = 16
19
20# check if key is in map
21'John' in m
22
23# remove entry from map
24del m['John']
25
26# get number of entries in map
27len(m)
```

Maps can be nested. Here’s an example of someone’s address information stored in a nested map.

``` 1information = {
2   'first_name': 'Mary',
3   'last_name': 'Doe',
5      'street': {
6         'number': 123,
7         'street': 'New York Blvd.',
8         'suite': 'C03'
9      },
10      'city': 'Beverly Hills',
11      'state': 'CA',
12      'zip': 90210
13   }
14}
```

### 2.6.1. Exercise

Let’s say we have data about Moesha and Shania; we know which toppings they like on their pizza and also which sports they like to watch on TV.

• If we wanted to order a pizza with all the toppings they both like, which toppings would we request?

• Which sports do they both like?

``` 1moesha = {
2   'name': 'moesha',
3   'toppings': {'cheese', 'jalepanos', 'bell pepper', 'mushroom'},
4   'sports': ['football', 'baseball', 'hockey']
5}
6
7shania = {
8   'name': 'shania',
9   'toppings': {'bell pepper', 'suasage', 'mushroom'},
11}
```

Solution.

```1# toppings they both like
2toppings = moesha['toppings'] & shania['toppings']
3print(toppings)
4
5# sports they both like
6# note we convert the lists to sets and then do an intersection
7sports = set(moesha['sports']) & set(shania['sports'])
8print(sports)
```

## 2.7. Tuple

A tuple looks and smells like a list. When declaring and initializing a tuple, however, we use parentheses `()`. There is a huge difference between a tuple and a list in that a tuple is `immutable` and a list is `mutable`. Immutable means that a tuple cannot be changed; elements cannot be added, removed or changed. Once a tuple is defined, you cannot change it.

``` 1# create a tuple
2numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9)
3
4# create a tuple without parentheses
5numbers = 1, 2, 3, 4, 5, 6, 7, 8, 9
6
7# access elements of a tuple
8x = numbers[0]
9y = numbers[1]
10z = numbers[3]
11
12print(x, y, z)
13
14# slicing a tuple
15x = numbers[0:5]
16
17print(x)
18
19# check membership
20result = 3 in numbers
21
22# concatenation
23numbers = (1, 2, 3, 4, 5) + (6, 7, 8, 9)
24
25# expansion
26t = (10, )
27u = t * 10
28
29# get the number of elements in tuple
30len(numbers)
```

Certain operations like sorting are not allowed on a tuple. As such, mixed variable types are often be stored in a tuple without worrying about the side-effects. Below, we have data on a person: name, age, weight and favorite sports.

```1data = ('John', 32, 150.5, ['baseball', 'basketball'])
```

One important concept with tuples is that of `unpacking` values from a tuple. Note the underscore `_` character to ignore or throw away unpacked values.

``` 1data = ('John', 32, 150.5, ['baseball', 'basketball'])
2
3# unpack the values of the tuple into variables
4name, age, weight, sports = data
5
6# ignoring unpacked values with underscore _
7name, _, _, sports = data
8
9# ignoring unpacked values with a wildcard and underscore
10# if we only care about unpacking the name and sports
11name, *_, sports = data
12
13# if we only care about unpacking the name and age
14name, age, *_ = data
```

It should make more sense to unpack elements from a tuple before operating on those elements, as doing so is more meaningful. Otherwise, we will operate on the elements through bracket-index notation and meaning and context will be lost.

``` 1data = ('John', 32, 150.5, ['baseball', 'basketball'])
2name, age, *_ = data
3
4# is this not more clear?
5print(f'name: {name}, age: {age}')
6
7# is this not unclear?
8# what is data[0]?
9# what is data[1]?
10print(f'name: {data[0]}, age: {data[1]}')
```

### 2.7.1. Exercise

Unpack the following tuple into the variables make, model and year.

```1car = ('Toyota', 'Camry', 2019)
```

Solution.

```1make, model, year = car
2print(f'make={make}, model={model}, year={year}')
```