4 Lists

message = ["Hello,"]
message.append("world")
print(" ".join(message))
## Hello, world

In chapter 2 Variables, you encountered the four basic data types of the Python programming language: integers, floats, Strings and Booleans. You also learned that apart from these four basic data types, Python knows numerous specialized types. Now it is time to encounter one group of these specialized data types: collections. You will learn about three types of collections, lists, tuples, and dictionaries in this chapter. Together, they make up a toolbox for storing information in a computer program.

4.1 Lists

a = [10, 5, 15, 25]
b = ["eggs", "bacon", "cheese"]
c = [4, "hello", 7.3, False]

Lists are one type of collection. The easiest way of creating a list is surrounding some values with cornered brackets [] and separating the values of the list with commas ,. The values that make up a list are called items or elements. Lists can contain any type of value or variable. From this it follows that lists can also contain other lists! A list that contains another list is called a list of lists, or nested list (you may also think of this phenomenon as listception, if you ever watched Christopher Nolan’s Inception (2010)).

a = 2
b = [a, 2*a]
c = [b, 6]
print(c)
## [[2, 4], 6]

A special type of list is the so-called empty list. An empty list is a list with no elements. Empty lists are denoted with [].

a = []

In a sense, lists are similar to Strings. Strings are basically ordered collections of characters. For example, the word Hello is an ordered collection of five characters: H,e, l, l, and o. In contrast to Strings, however, the elements of lists can be of any type. Ordered collections such as strings and lists are also called sequences.

Lists are ordered collections of values. However, a list being ordered has nothing to do with how humans may be inclinded to order the elements of a list. For example, you may want to order a list a with three elements "A", "B", and "C" according to their alphabetic order: a = ["A", "B", "C"]. However, for lists, the value of an element is irrelevant for its position in the list. Lists are not ordered because they grasp some underlying semantics about their elements according to which they come up with an order. In fact, element values are arbitrary for a list. Instead, lists are called ordered because they allocate a certain position in memory to each element. Each list element occupies a unique position in memory. Elements of a list are accessed by querying the list at specified positions, so-called indices. Accessing a list at a specified index, the value located at that position in memory is returned. The index operator [] is used to access list elements at specified indices, like so

a = [1, 2, 3]
print(a[0])
## 1
print(a[1])
## 2

The expression inside the brackets of the index operator (in this case the integers 0 and 1) specifies the index of the to-be selected element. Each element inside a list has a unique index, an integer describing the element’s position in the list. One major cause of errors surrounding lists is that indices start at 0, not at 1, as you might expect. After all, to us it feels natural to start counting at 1. As you can see below, this means that the first element of a list is accessed by indexing 0.

a = ["Hello", "World", "!"]
print(a[0])
## Hello
print(a[2])
## !

Why do indices start at 0, instead of 1? As you might already expect, it has to do with how computers store information in memory. A list serves as a pointer, a reference to a memory location. The expression list[i] then refers to a memory position i-steps away from the starting element. This means that the index is used as an offset. The first element of a list is located at exactly the position the list refers to (which means that the offset is 0). Hence, the first element of a list is located at index 0.

4.1.1 Lists are mutable

In contrast to Strings, lists are mutable sequences. This means that even after a variable is assigned a list as value, specific elements of this list can be changed without reassigning a completely new list! You can use the index operator to mutate specific list items.

shoppinglist = ["appels", "bananas", "tomatoes"]
shoppinglist[2] = "peaches"
print("Updated shopping list: " + ", ".join(shoppinglist))
## Updated shopping list: appels, bananas, peaches
a = [1,2]
a[0] = 10
print(a)
## [10, 2]

Using the index operator, you can also access (and change!) several elements at a time using so-called list slices:

a = [1, "a", 2, "b", 3, "c"]
print(a[1:4])
## ['a', 2, 'b']
print(a[0:2])
## [1, 'a']
a[0:2] = "d"
print(a)
## ['d', 2, 'b', 3, 'c']

The indices around the : colon indicate the starting and ending index of the selected list slice. Note that a list slice will always include the element located at the starting index, but exclude the element located at the ending index. To include 2 in the second list slice you would thus need to access a[0:3], or simplified a[:3]. The latter meaning “every element up until, but excluding index 3”.

Note that the statement a[0:2] = d mutates both elements, 1 and "a" into a single new item "d". This means that the statement did not only change some elements of a, but also a’s total number of elements!

When no starting or ending index is specified, the : expression selects all elements of a list and can be used for cloning lists.

a = [1, "a", 2, "b", 3, "c"]
aCopy = a[:]
print(aCopy)
## [1, 'a', 2, 'b', 3, 'c']

But watch out, you cannot use the index operator to add new elements to a list. To do so, you would need to access a new index, an index not yet claimed by an existing list element. Trying to access an index outside of the current range of indices will produce an index out of range error.

a = [1,2]
a[2] = 10
## Error in py_call_impl(callable, dots$args, dots$keywords): IndexError: list assignment index out of range
## 
## Detailed traceback:
##   File "<string>", line 1, in <module>
print(a)
## [1, 2]

Luckily, there are other ways of adding elements to a list.

a = []
a.append(1)
print(a)
## [1]
a.append(2)
print(a)
## [1, 2]

The append method adds the specified element at the end of a given list. You can use the extend method to add multiple values of another list (or other type of collection) to your list.

a = [1,2]
b = [3,4]

a.extend(b)
print(a)
## [1, 2, 3, 4]

Note that there is a difference between appending a list and extending your list with another list.

a = [1,2]
b = [3,4]

a.append(b)
print(a)
## [1, 2, [3, 4]]

In the above example, extending a with b causes the elements stored in b to be appended to a sequentially, each of them constituting a new element in a. In contrast, the whole list b is regarded as an element of a when b is appended to a. Because lists are mutable, you can sequentially fill them with elements, one by one. This is very handy for storing values you generate throughout your program.

###A word about class specific functions By now, you have seen a few examples of class-specific functions, such as append() for lists or join() for strings. Even though a detailed explanation of functions (also called methods) is postponed to Chapter 6, a quick introduction to the terminology of objects, classes, and class-specific functions will help you make the most of your lists and other collections. For now, you can see functions as pieces of reusable code that specify what to do with some input values.

When you create a variable a and assign a value to it, say [4,5], you can think of it as creating an object (i.e. an instance) of the Python class list. The list class has been programmed by the developers of the Python language, same as any other built-in Python class, such as integers and strings. Classes are blueprints, a specification of how to build certain objects. Engineers use blueprints to build cars, buildings, bridges and more. Chefs use recipes to put together meals. Python classes are the same in that they specify how objects of a certain type are programmed internally when you create one of them. A class has built-in methods that can be used by any object that has been created using the class’ blueprint. And this is what you basically do whenever you surround a number of values with cornered brackets. You create a list according to the blueprint of the Python class list. It is very useful that your list inherits functions from its blueprint. It means that without any effort on your part your lists have a variety of functionality at their disposal. They can immediately use a range of built-in methods such as the append() method.

a = [4,5]
a.append(6)
print(a)
## [4, 5, 6]

The append() method adds the value specified between the brackets to the end of the list. Typing help(list) in your console will give you a complete list of built-in functions of the class list and what they do.

What is the take-home message of this excursion to object-orientation? Well, make use of built-in class functions as much as you can! They provide a tremendous amount of functionality which you are likely going to need and want, written in neat code which makes them very efficient to use, too!

The interested reader can find more information on Python classes here.

4.2 Tuples

Much like lists, tuples are ordered collections of values, but with less exentensive functionality and their unique characteristic being that they are immutable. Once you created a tuple in memory, you cannot change its elements.

thorndike = ("Edward", "Lee", "Thorndike", 1874, "Law of effect", "Law of exercise")
thorndike[4] = "Law of recency"
## Error in py_call_impl(callable, dots$args, dots$keywords): TypeError: 'tuple' object does not support item assignment
## 
## Detailed traceback:
##   File "<string>", line 1, in <module>

Tuples are usually used when you assume that a collection of values will not change in the course of your program. They are records of related information, chunked together so that we can use them as a single entity. In the Stroop Task program for instance, we saw that tuples were used to chunk together RGB combinations that make up a color. The Pygame module used these tuples to generate color in the Stroop Task.

Tuples are immutable. However, if you really need to change the contents of an already existing tuple, you can always assign a new value to the variable which holds the tuple as a value.

thorndike = ("Edward", "Lee", "Thorndike", 1874, "Law of effect", "Law of exercise")
thorndike = thorndike[:] + ("Law of recency",)
print(thorndike)
## ('Edward', 'Lee', 'Thorndike', 1874, 'Law of effect', 'Law of exercise', 'Law of recency')

Note the trailing comma in the second line ("Law of recency",). Without the comma at the end of the parentheses, Python treats the content of a one-element tuple such as ("Law of recency") as belonging to the data type of the element (in this case a str). As a result, a type error is thrown when you try to concatenate the thorndike tuple and ("Law of recency").

thorndike = ("Edward", "Lee", "Thorndike", 1874, "Law of effect", "Law of exercise")
thorndike = thorndike[:] + ("Law of recency")
## Error in py_call_impl(callable, dots$args, dots$keywords): TypeError: can only concatenate tuple (not "str") to tuple
## 
## Detailed traceback:
##   File "<string>", line 1, in <module>

Python has a very powerful tuple assignment feature that allows a tuple of variable names on the left of the assignment operator = to be assigned to a tuple of values, like so

thorndike = ("Edward", "Lee", "Thorndike", 1874)
(name, middle_name, surname, born) = thorndike
print(name)
## Edward
a, b = "Hello", "World"
print(a)
## Hello

The brackets () are optional in a tuple assignment. Using tuple assignment, you can easily perform several variable assignments in just one line!

4.3 Dictionaries

Dictonaries share similarities with real-life address books where you can find a person’s contact details by looking up his or her name.

address_book = {"studyadviser-PSY": "studyadviser-psy[at]utwente.nl",
                "studentservices" : "studentservices[at]utwente.nl",
                "ICT-helpdesk"   : "servicedesk-ict[at]utwente.nl"
                }

print(address_book["studyadviser-PSY"])
## studyadviser-psy[at]utwente.nl

Dictionaries associate keys (e.g. a name) with values (e.g. contact details). The key:value pairs of a dictionary are separated by commas. Each pair contains a key and a value separated by a colon :. key:value pairs are always one-to-one mappings. This means that you cannot map the same key to several values, like so

address_book = {"studyadviser-PSY": "studyadviser-psy[at]utwente.nl",
                "studyadviser-PSY": "Cubicus, room C116"
                }
                
print(address_book["studyadviser-PSY"])
## Cubicus, room C116
print("Number of key:value pairs in address_book: %d" % len(address_book.keys()))
## Number of key:value pairs in address_book: 1

As you can see, the first mapping of the key "studyadviser-PSY" to "studyadviser-psy[at]utwente.nl" has been overwritten by the second mapping of the key to "Cubicus, room C116". In total, address_book now only contains a single key:value pair. As with lists and tuples, values are arbitrary for dictionaries. This means that while you cannot map the same key to several values, you can map the same value to multiple keys.

address_book = {"studyadviser-PSY": "studyadviser-psy[at]utwente.nl",
                "studyadviser-PSY_email": "studyadviser-psy[at]utwente.nl"
                }
                
print("Number of key:value pairs in address_book: %d" % len(address_book.keys()))
## Number of key:value pairs in address_book: 2

Dictionaries require their keys to be immutable and unique. As you above, you cannot have two keys named "studyadviser-PSY" in the address_book. This also means that certain data types are unsuitable as dictionary keys, like lists.

d = {['a']: 'b'}
## Error in py_call_impl(callable, dots$args, dots$keywords): TypeError: unhashable type: 'list'
## 
## Detailed traceback:
##   File "<string>", line 1, in <module>

Whenever you try to use a mutable object (like lists) as a key, a TypeError will be thrown. Because lists are mutable (you can update their elements), they are unhashable. Without going into the details of hash functions here, a hash is another representation of an object. It is a transformation of the object’s length sequence of bytes into a fixed length sequence. Hash functions are used in cryptographic algorithms, in digital signatures, manipulation detection, password storage and more. Hash functions are constructed so that calculating an object’s hash representation is simple, but retrieving the original object is difficult without knowing the function used to hash the object in the first place. You can imagine that things start to get messy if the object itself can change after its hash has been calculated. A hash is a momentary snapshot of an object. It is impossible to retrieve the “latest version” of a changable object from its hash representation, even if you know its hash function. Dictionaries themselves are also mutable (and thus, unhashable) and cannot be used as keys, by the way.

Dictionaries are unordered collections. Dictionaries do not have a sequential representation of their elements. Unlike sequences, such as lists and tuples, the elements of a dictionary cannot be accessed using indices. Values stored in a dictionary can be accessed and changed through their respective keys, like so

address_book = {"studyadviser-PSY": "studyadviser-psy[at]utwente.nl",
                "studentservices" : "studentservices[at]utwente.nl",
                "ICT-helpdesk"   : "servicedesk-ict[at]utwente.nl"
                }
                
address_book["studentservices"] = ("studentservices[at]utwente.nl", "0534892124")
print("The telephone number of the student services is", str(address_book["studentservices"][1]))
## The telephone number of the student services is 0534892124

Apart from updating existing dictionary entries, you can obviously also add and remove entries of a dictionary. Use the del statement to remove dictionary entries.

address_book = {"studyadviser-PSY": "studyadviser-psy@utwente.nl ",
                "studentservices" : "studentservices@utwente.nl",
                "ICT-helpdesk"   : "servicedesk-ict@utwente.nl"
                }
                
address_book["studentUnion"] = "studentunion@union.utwente.nl"
print(address_book)
                
## {'studyadviser-PSY': 'studyadviser-psy@utwente.nl ', 'studentservices': 'studentservices@utwente.nl', 'ICT-helpdesk': 'servicedesk-ict@utwente.nl', 'studentUnion': 'studentunion@union.utwente.nl'}
del address_book["ICT-helpdesk"]
print(address_book)
## {'studyadviser-PSY': 'studyadviser-psy@utwente.nl ', 'studentservices': 'studentservices@utwente.nl', 'studentUnion': 'studentunion@union.utwente.nl'}

4.4 Putting collections to use

Lists, tuples and dictionaries are readily used in interactive programs, such as the Stroop Task program. Collections help structure user input and the subsequent storage of user input in computer memory. Structuring user input makes later retrieval of information easier. Below you see a code snippet from the Stroop Task program.

KEYS     = {"red": K_b,
            "green": K_n,
            "blue": K_m}
RT = []
trial_number = 0    
    
while True:
    pygame.display.get_surface().fill(BACKGR_COL)        

    # Changing states
    for event in pygame.event.get():                        
        if STATE == "welcome":
             if event.type == KEYDOWN and event.key == K_SPACE:
                 STATE = "present_trial"
                 print(STATE)
                    
        if STATE == "present_trial":
             trial_number = trial_number + 1
             this_word  = pick_color()
             this_color = pick_color()
             time_when_presented = time()
             STATE = "wait_for_response"
             print(STATE)
                    
        if STATE == "wait_for_response":
            if event.type == KEYDOWN and event.key in KEYS.values():
                time_when_reacted = time()
                this_reaction_time = time_when_reacted - time_when_presented
                RT.append(this_reaction_time)
                this_correctness = (event.key == KEYS[this_color])
                STATE = "feedback"
                print(STATE)

                
        if STATE == "feedback":
            if event.type == KEYDOWN and event.key == K_SPACE:
                if trial_number < 20:
                    STATE = "present_trial"
                else:
                    STATE = "goodbye"
                print(STATE)
            
        if event.type == QUIT:
            STATE = "quit"

Note how the variable RT is used to keep track of the user’s reaction times throughout the trials. The variable this_reaction_time is overwritten in each trial. This means, that at the end of the program, when all trials are completed, this_reaction_time only contains the last value assigned to it during the 20th trial. All other reaction times were long erased from computer memory. But wait, what if we want to calculate a user’s mean reaction time once the experiment is finished? In order to do so, we need some way of saving the reaction times from trial to trial. They need to persist until the last trial is completed. This is exactly where collections step into the picture. Collections are capable of storing multiple values at the same time and they can be mutated iteratively (one reaction time per trial). Hence, we append the calculated reaction time to a list in each trial.

In the end, you as a programmer still need to decide how to proceed with the collected reaction times. Do you want to print their mean to the screen, export them out of the program, or combine them with data gathered from other experimental subjects? It is up to you. Using collections, at least you have a user’s reaction times at your disposal, even after they completed the experiment.

4.5 Common errors

  • The by far most occurring errors involving lists are index out of range errors. I think it is fair to say that they make up a large amount of all programming errors. An index out of range error is thrown when you try to access an index that does not exist in a sequence.
shoppinglist = ["milk", "eggs", "bread", "appels"]
print shoppinglist[4]
## [1] "Error: Missing parentheses in call to 'print'. Did you mean print(shoppinglist[4])? (<string>, line 2)"

You will usually encounter this error as a result of confusing the starting index 0 with 1. Against all intuition, in a list of four elements, the last element is stored at index 3, not at index 4. It helps to keep in mind that the indices of your sequences always have a range one shorter than the number of elements in your list. For a list with four elements, the positive index range is 0 to 4 minus 1, thus 3.

shoppinglist = ["milk", "eggs", "bread", "appels"]
print(shoppinglist[3])
## appels
  • Another common mistake surrounding collections concerns the immutability of tuples. In particular, trying to change the content of a tuple will result in a TypeError. Tuples are immutable, meaning that you cannot change their content after their initialization. You can, however, re-assign the variable name of an existing tuple to a new tuple containing different values.
a = (1,2,4)
b[2] = 3
## Error in py_call_impl(callable, dots$args, dots$keywords): TypeError: 'str' object does not support item assignment
## 
## Detailed traceback:
##   File "<string>", line 1, in <module>
a = (1,2,4)
print(a)
## (1, 2, 4)
b = (1,2,3)
print(b)
## (1, 2, 3)
  • Concerning dictionaries, you will most probably not escape one or another KeyError. A KeyError is thrown when you try to access a key that does not exist in the dictionary.
d = {}
print(d['a'])
## Error in py_call_impl(callable, dots$args, dots$keywords): KeyError: 'a'
## 
## Detailed traceback:
##   File "<string>", line 1, in <module>

The same is likely to occur when you try to use indices to access the entries of a dictionary

d = {'a': 1}
print(d[0])
## Error in py_call_impl(callable, dots$args, dots$keywords): KeyError: 0
## 
## Detailed traceback:
##   File "<string>", line 1, in <module>

Dictionaries are the only unordered type of collection you encountered in this chapter. It occurs now and then that one assumes that a dictionary can be treated as other common types of collections, such as lists or tuples.

4.6 Debugging

Here are some tips and tricks on how to debug errors that potentially originate from your collections.

  1. Regularly checking the length of your collections can be very helpful to confirm that your code does indeed what you expect it to do. Take the example of RT, the list we made to keep track of a participant’s reaction times throughout the Stroop Task program. At the end of the experiment, you would expect the list to contain 20 elements, given that RT was initialized as an empty list and that the experiment had 20 trials. By checking the length of RT, you can immediately see whether your code indeed stored one reaction time per trial. RT should have a length of 20 after the experiment. You can check the length of a collection using the len() method, like so
a = [3, 4]
print(len(a))
## 2
  1. Dictionaries have a very useful built-in method that represents their keys as a list.
d = {'a': 1,
     'b': 2}
     
print(d.keys())
## dict_keys(['a', 'b'])

This comes in handy when you keep getting a KeyError while you are convinced that your dictionary should contain a certain key.

d = {'a ': 1,
     'b': 2}
     
print(d['a'])
## Error in py_call_impl(callable, dots$args, dots$keywords): KeyError: 'a'
## 
## Detailed traceback:
##   File "<string>", line 1, in <module>

You can use in to check whether a candidate key is among the keys of the dictionary

d = {'a ': 1,
     'b': 2}
     
print('a' in d.keys())
## False

In this case, a typing error is the culprit. Instead of 'a', 'a ' with a whitespace was set as the first key of d.

Alternatively, you can use a simple conditional constructions and not in to make sure that you do not overwrite any existing keys

d = {'a': 1,
     'b': 2}

if 'a' not in d.keys():
    d['a'] = 0

print(d)
## {'a': 1, 'b': 2}

Finally, you should know that the output list produced by the keys() method can be confusing at times. It is possible that your Python interpreter returns a different list of keys than the same code snippet d.keys() produces on another system. This has to do with how dictionaries are stored internally in computer memory. Here as well hash functions are utilized for efficiency reasons. As a result, the order of the keys in a dictionary is unspecified (which is why you cannot use the index operator to access elements of a dictionary). In practice, it means that 'a' is not necessarily the first element in a list produced by d.keys(). Rest assured, in practice, this peculiarity is rather insignificant.

4.7 Exercises

4.7.1 Exercise 1. Indexing

What is the output of the following code snippets?

a = [6, 7]
b = [4, 5]
b.append(a)

print(b)
d = {1: 'a',
    'a': 1}
    
print(d[1])
a = [1]
b = ('a', 2)
a.extend(b)

print(a[1])
a, b = (['a', 'd'], ['b', 'c'])

print(b[0])
a = [1, 2, 3]

print(a[-1])
a = (1, 2, [3, 4], 5)

print(a[2][1])

4.7.2 Exercise 2. Debugging

Will the following code snippets throw an error? If anything goes wrong, why does it go wrong?

a, b = 'Sigmund', 'Freud', (1856, 1939)
  • No error is thrown, a and bare assigned the values 'Sigmund' and 'Freud' respectively, and (1856, 1939) will not persist in computer memory.
  • A ValueError is thrown. There are too many values on the right side of the equals sign = to unpack.
  • A NameError is thrown. The variables a and b have not been assigned yet and can therefore not be compared with other values.
a = [1, 2]
b = (3, 4)

a.append(b)
print(a[3])
  • Nothing goes wrong, the output is 4 because 4 is located at index 3 after b is appended to a.
  • A TypeError is thrown. b cannot be appended to a because lists cannot have tuples as elements.
  • An IndexError is thrown. After appending b, a has three elements. 3 is not a valid index.
a = ('a', [1, 2])

a[1].append(3)
  • A TypeError is thrown because tuples are immutable and do not support item assignment.
  • No error is thrown, 3 is appended to [1, 2].
  • An AttributeError is thrown, tuples do not have an append method.
a = {('a', 'b'): 3}

print(a.keys())
  • No error is thrown, the list of keys contains one element, ('a', 'b').
  • A TypeError is thrown. Tuples cannot be hashed because they are changable and therefore unsuitable as dictionary keys.
  • No error is thrown. By means of tuple assignment, the dictionary has two keys, a and b.

4.7.3 Exercise 3. Mini programs

What is the output of the following mini programs?

a = {}

print(a.keys())
  • []
  • 0
  • A KeyError because a is empty and has no keys.
a = []
b = ([1, 2], [3, 4], [5, 6])

a.extend(b)
print(a[1])
  • [1, 2]
  • 2
  • [3, 4]
a = ('a', ('b', 'c'))

print('b' in a)
  • True
  • False
  • A TypeError is thrown because the in operator cannot be used with tuples.
a = [{'a': 1 }, {'a': 2}]

if 'a' in a[0]:
    print(a[0]['a'])
elif 'a' in a[1]:
    print(a[1]['a'])
  
  • 1
  • 2
  • 1 and 2

4.7.4 Exercise 4. Shopping list

shoppinglist = ["bread","cheese","jam","milk","oatmeal","blueberries","oranges","apples"]
shoppinglist[0] = "buns"
shoppinglist = shoppinglist + ["chocolate"]
del shoppinglist[2]

shoppinglist_mum = ["eggs","yoghurt","potatoes","salmon"]
shoppinglist += shoppinglist_mum
del shoppinglist[10]

ingredients_muffins = ["icing sugar","whipping cream","lemons","flower","vanilla sugar","eggs","mandarines","baking powder","sugar","margarine"]

shoppinglist.append(ingredients_muffins)
del shoppinglist[11][6]
shoppinglist[8:11] = [shoppinglist[8:11]]

del ingredients_muffins[7]

The above shopping list has been subject to several changes since it has been written. Standing in the supermarket, you want to know the contents of the final shopping list. Which groceries do you have to buy?

You can check your answer afterwards by running the code.

4.7.5 Exercise 5. Dictionaries

famous_psychologists = {"Freud":("Sigmund", "Freud", (1856,1939), "Psychoanalysis"),
                        "Piaget":("Jean", "Piaget", (1896,1980), "Theory of Cognitive Development"),
                        "Skinner":(("Burrhus", "Frederic"), "Skinner", (1904,1990), "Operant Conditioning"),
                        }
                      
erikson = ("Erik", "Erikson", (1902,1994), "Theory of Psychological Development")
famous_psychologists["Erikson"] = erikson

more_on_Skinner = {"Schedules of Reinforcement":("positive reinforcement", "negative reinforcement", "extinction"),
                   "Skinner Box":("pigeon","lever","food"),
                  }
famous_psychologists["Skinner"] = famous_psychologists["Skinner"][:3] + ("Behaviorism",) +         (famous_psychologists["Skinner"][3],) + (more_on_Skinner,)

Using the dictionary famous psychologists and the above changes made to the dictionary:

  • Try to understand the changes made to the original dictionary by writing down the content of the following print statements
print(famous_psychologists["Erikson"][:3])
print(famous_psychologists["Piaget"][3:])
print(famous_psychologists["Freud"][2][0])
print(famous_psychologists["Skinner"][0][1])
print(famous_psychologists["Skinner"][5].keys()[1])

word = famous_psychologists["Skinner"][5].keys()[0]
print(famous_psychologists["Skinner"][5][word][0])
  • Afterwards, you may check your answers by running the code. Pay attention that your own answers match exactly.

4.7.6 Exercise 6. Element selection

For the following data structures, give the code by which you can access the specified element.

dinner = ["minced beef", "tomatoes", "pasta", "onions", "pasta sauce", "courgette"]
shoppingList = [dinner, "bread", "milk", "cornflakes", "cheese"]
grades = {"p1": ("Judith",21,"female","B-PSY",(5.6,7.7,7.3)),
          "p2": ("Menno",19,"male","B-CREATE",(8.6,6.9,7.4)),
          "p3": ("Jan",19,"male","B-CREATE",(3.9,4.5,8.9)),
          "p4": ("Eva",20,"female","B-MATH",(8.0,7.0,9.1)),
          "p5": ("Sophia",22,"female","M-PSY",(4.9,6.7,7.6)),
          "p6": ("Jeroen",25,"male","M-BME",(8.5,8.5,8.5)),
          "p7": ("Max",18,"male","B-IBA",(7.9,2.0,6.5))
         }
  1. milk in shoppingList
  2. minced beef in shoppingList
  3. The study of Jan in grades
  4. The age of Sophia in grades
  5. The name of participant 6 in grades
  6. Judith’s grade on the third partial exam in grades
  7. The grade of participant 5 on the first partial exam in grades
  8. The maximum grade achieved on the second partial exam

4.7.7 Exercise 7. Adjust a dictionary data set

The data set below originates from a (fictive) language course given at the University of Twente. During the course, the following information was stored about the participants: age, gender, nationality, study programme, for each lesson, whether the participant was present or not (True indicates presence during the lesson and False absence), and the paricipant’s score on the final exam.

dataset = {'p1':[21,"Female","Dutch","B-Psychology",[True,False,True,False,False],5.2],
           'p2':[20,"Female","Dutch","B-Psychology",[True,True,True,False,True],8.4],
           'p3':[21,"Female","Dutch","B-Applied_Mathematics",[False,True,True,False,True],7.8],
           'p4':[23,"Male", "German","B-Communication_Science",[True,True,"n/a","n/a",True],8.8],
           'p5':["n/a","n/a","Dutch","M-Business_Administration",[False,False,True,True,True],7.6],
           'p6':[19,"Male","Swedish","B-Computer_Science",[True,False,False,True,False],7.5],
           'p7':[19,"Male","German","B-Communication_Science",[True,True,False,True,True],5.4]
           }

The lecturer has to perform some last minute changes to the data set before handing it in for statistical examination. Perform the following changes to the data set by accessing the relevant elements.

  1. After taking a resit, participant 1 and participant 7 did pass the course. Participant 1 scored a 6.1 on the resit and participant 7 a 7.4.
  2. Participant 5 forgot to put her age and gender on the registration form. Participant 5 is female and 23 years old.
  3. The docent forgot to sign the presence of participant 4 during two lessons. Participant 4 was present during all lessons.
  4. During the course, participant 2 changed her study programme from B-Psychology to B-Health Sciences.
  5. After the final examination, it was revealed that participant 4 cheated during the exam. The examination board decided to void the student’s achievements on the exam. In such a case, the additional note expelled is added to the student’s record, indicating the student’s misbehaviour.

4.7.8 Exercise 8. A dictionary data set

Fill in the participant information given in the table below in a Python dictionary with the following structure:

participants = {participant_no:(gender, age, nationality, profession)}
Participant No. Gender Age Nationality Profession
1 Male 19 Dutch Student
2 Male 47 Dutch Pharmacist
3 Male 31 Italian PhD Student
4 Female 22 German Student
5 Female 46 Dutch Florist
6 Male 27 Dutch Student
7 Female 22 Dutch Police trainee
8 Female 26 Indian Architect
9 Male 18 American Student
10 Male 20 Chinese Student

Using Python and by accessing the relevant elements in the dataset

  1. Calculate the average age of the participants
  2. Calculate the standard deviation of the age variable
  3. Calculate the maximum and minimum of the age variable

Hint: Libraries provide built-in methods beyond the repertoire of the standard Python language. For instance, NumPy provides all kinds of methods for statistical operations in Python. You can import a library by typing import (library name) and make use of library-specific methods like this (library name).(method). Take a look at the documentation of the NumPy library.

4.7.9 Exercise 9. Stroop extension

In this exercise you will implement a conditional execution of the interactive Stroop program. Imagine that you want to examine whether the number of colors influences the reaction time of participants in the Stroop experiment. In particular, you have gathered ten participants whom you randomly assigned to either a three or a five word version of the Stroop task. The table below summarizes which participant is assigned to which condition.

Participant No. Condition
1 Stroop 3
2 Stroop 3
3 Stroop 5
4 Stroop 3
5 Stroop 5
6 Stroop 5
7 Stroop 5
8 Stroop 3
9 Stroop 5
10 Stroop 3

For this exercise, a modified version of the Stroop task is given. In ch4ex6Stroop.py, a rudimentary implementation of user console input is provided. In two additional STATES, the user enters his participant number and the entered number is stored for the rest of the program run. The modified script has a function pickColor5(), which implements the random selection of words and colors for the five-color version.

In order to implement the comparative Stroop version program (three vs. five colors) program, consider the following steps:

  • Open ch4ex6Stroop.py and scan the changes to the original code. Try to understand the changes performed to the code.
  • Incorporate the information contained in the table above on the condition assignment of the ten participants. Which data structure will you use for storing this information?
  • Prepare the code for both Stroop task versions, a version with three words, three colors, and three buttons and the same for the five-word version. Choose any two additional colors.
  • Think about which places in the program need to be adapted and which of them need adaptation depending on the condition.

4.8 Think further