Advanced Datatypes#

These notes follow the official python tutorial pretty closely: http://docs.python.org/3/tutorial/

Lists#

Lists group together data. Many languages have arrays (we’ll look at those in a bit in python). But unlike arrays in most languages, lists can hold data of all different types – they don’t need to be homogeneos. The data can be a mix of integers, floating point or complex #s, strings, or other objects (including other lists).

A list is defined using square brackets:

a = [1, 2.0, "my list", 4]
a
[1, 2.0, 'my list', 4]

We can index a list to get a single element – remember that python starts counting at 0:

a[2]
'my list'

Like with strings, mathematical operators are defined on lists:

a*2
[1, 2.0, 'my list', 4, 1, 2.0, 'my list', 4]

The len() function returns the length of a list

len(a)
4

Unlike strings, lists are mutable – you can change elements in a list easily

a[1] = -2.0
a
[1, -2.0, 'my list', 4]
a[0:1] = [-1, -2.1]   # this will put two items in the spot where 1 existed before
a
[-1, -2.1, -2.0, 'my list', 4]

Just like everything else in python, a list is an object that is the instance of a class. Classes have methods (functions) that know how to operate on an object of that class.

There are lots of methods that work on lists. Two of the most useful are append, to add to the end of a list, and pop, to remove the last element:

a.append(6)
a
[-1, -2.1, -2.0, 'my list', 4, 6]
a.pop()
6
a
[-1, -2.1, -2.0, 'my list', 4]

Quick Exercise

An operation we’ll see a lot is to begin with an empty list and add elements to it. An empty list is created as:


 a = []
 
  • Create an empty list

  • Append the integers 1 through 5 to it.

  • Now pop them out of the list one by one.

copying lists#

copying may seem a little counterintuitive at first. The best way to think about this is that your list lives in memory somewhere and when you do

a = [1, 2, 3, 4]

then the variable a is set to point to that location in memory, so it refers to the list.

If we then do

b = a

then b will also point to that same location in memory – the exact same list object.

Since these are both pointing to the same location in memory, if we change the list through a, the change is reflected in b as well:

a = [1, 2, 3, 4]
b = a  # both a and b refer to the same list object in memory
print(a)
a[0] = "changed"
print(b)
[1, 2, 3, 4]
['changed', 2, 3, 4]

if you want to create a new object in memory that is a copy of another, then you can either index the list, using : to get all the elements, or use the list() function:

c = list(a)   # you can also do c = a[:], which basically slices the entire list
a[1] = "two"
print(a)
print(c)
['changed', 'two', 3, 4]
['changed', 2, 3, 4]

Things get a little complicated when a list contains another mutable object, like another list. Then the copy we looked at above is only a shallow copy.

When in doubt, use the id() function to figure out where in memory an object lies (you shouldn’t worry about the what value of the numbers you get from id mean, but just whether they are the same as those for another object)

print(id(a), id(b), id(c))
140131038329408 140131038329408 140131038273152

Or use the is operator

a is b
True
a is c
False

There are lots of other methods that work on lists (remember, ask for help)

my_list = [10, -1, 5, 24, 2, -1, 9]
my_list.sort()
my_list
[-1, -1, 2, 5, 9, 10, 24]
my_list.count(-1)
2

We can also insert elements

a.insert(3, "my inserted element")
a
['changed', 'two', 3, 'my inserted element', 4]

joining two lists is simple. Like with strings, the + operator concatenates:

b = [1, 2, 3]
c = [4, 5, 6]
d = b + c
d
[1, 2, 3, 4, 5, 6]

Dictionaries#

A dictionary stores data as a key:value pair. Unlike a list where you have a particular order, the keys in a dictionary allow you to access information anywhere easily:

my_dict = {"key1":1, "key2":2, "key3":3}
my_dict["key1"]
1

you can add a new key:pair easily, and it can be of any type

my_dict["newkey"] = "new"
my_dict
{'key1': 1, 'key2': 2, 'key3': 3, 'newkey': 'new'}

You can also easily get the list of keys that are defined in a dictionary

keys = list(my_dict.keys())
keys
['key1', 'key2', 'key3', 'newkey']

and check easily whether a key exists in the dictionary using the in operator

print("key1" in my_dict)
print("invalidKey" in my_dict)
True
False

Quick Exercise

Create a dictionary where the keys are the string names of the numbers zero to nine and the values are their numeric representation (0, 1, … , 9)

List Comprehensions#

list comprehensions provide a compact way to initialize lists. Some examples from the tutorial

squares = [x**2 for x in range(10)]
squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Quick Exercise

Use a list comprehension to create a new list from squares containing only the even numbers. It might be helpful to use the modulus operator, %

Tuples#

tuples are immutable – they cannot be changed, but they are useful for organizing data in some situations. We use () to indicate a tuple:

a = (1, 2, 3, 4)
a
(1, 2, 3, 4)

We can unpack a tuple:

w, x, y, z = a
w
1

Since a tuple is immutable, we cannot change an element:

a[0] = 2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[30], line 1
----> 1 a[0] = 2

TypeError: 'tuple' object does not support item assignment

But we can turn it into a list, and then we can change it

z = list(a)
z[0] = "new"
z
['new', 2, 3, 4]

It is often not clear how tuples differ from lists. The most obvious way is that they are immutable. Often we’ll see tuples used to store related data that should all be interpreted together. A good example is a Cartesian point, (x, y). Here is a list of points:

points = []
points.append((1,2))
points.append((2,3))
points.append((3,4))
points
[(1, 2), (2, 3), (3, 4)]

we can even generate these for a curve using a list comprehension:

points = [(x, 2*x + 5) for x in range(10)]
points
[(0, 5),
 (1, 7),
 (2, 9),
 (3, 11),
 (4, 13),
 (5, 15),
 (6, 17),
 (7, 19),
 (8, 21),
 (9, 23)]