## 4.1 Dictionaries

• A dictionary is like a list, but more general. In a list, the index positions have to be integers; in a dictionary, the indices can be (almost) any type.

• 
>>> x = {} #This is False
>>> print(x)
{}

• The empty dictionary can be written as dict(). Similarly, an empty list can be list().

• You can think of a dictionary as a mapping between a set of indices (which are called keys) and a set of values.

• 
>>> x['one'] = 'uno'
>>> print(x)
{'one': 'uno'}

• In general, the order of items in a dictionary is unpredictable.

• 
>>> x = {'one': 'apple', 'two': 'banana', 'three': 'orange'}
>>> print(x)
{'one': 'apple', 'three': 'orange', 'two': 'banana'}

>>> print(x['two'])
'banana'


• 
alien = {}
alien['color'] = 'green'
alien['point'] = 5
print(alien)

#output
{'color': 'green', 'points': 5}


• Modifying Values in a Dictionary

• 
alien['color'] = 'yellow'
print(alien)

#output
{'color': 'yellow', 'points': 5}

• Removing Key-Value Pairs

• 
del alien['points']
print(alien)

#output
{'color': 'yellow'}

• Merge two dictionaries


dict1 = { "name":"owen", "age": 18 }
dict2 = { "birthday": "1999-11-22"}

x = dict( dict1, **dict2 )
print(x)

#output
{'name': 'owen', 'age': 18, 'birthday': '1999-11-22'}

• Work with conditional execution


alien = {'x': 0, 'y': 25, 'speed': 'fast'}
print("Original x-position: " + str(alien['x']))

if alien['speed'] == 'slow':
x_increment = 1
elif alien['speed'] == 'fast':
x_increment = 2

alien['x'] = alien['x'] + x_increment
print("New x-position: " + str(alien['x']))

#output
Original x-position: 0
New x-position: 2


### IN operator

• The in operator can determine whether an element is contained in a list.

• 
>>> x = ['one', 'two',  'three']
>>> 'one' in x
True
>>> 'four' in x
False

• The in operator works on dictionaries. (keys)

• 
>>> x = {'one': 'apple', 'two': 'banana', 'three': 'orange'}
>>> 'one' in x
True
>>> 'uno' in x
False

• To see whether something appears as a value in a dictionary, you can use the method .values(), which returns the values as a list, and then use the in operator:


>>> x = {'one': 'apple', 'two': 'banana', 'three': 'orange'}
>>> y = list(x.values()) #list(x.keys())
>>> 'orange' in y
True


### Lists vs. Dictionaries

• Lists: in operator, insert(), del (slow)

• Dictionaries: in operator, add key-value pair, del (fast)

• Hash Function (do not make repeated keys)

### Nesting

• You can nest a set of dictionaries inside a list, a list of items inside a dictionary, or even a dictionary inside another dictionary. A list or a dictionary cannot be the key (The key should be immutable).

• Dictionaries in a list

• 
alien_0 = {'color': 'green', 'points': 5}
alien_1 = {'color': 'yellow', 'points': 10}
alien_2 = {'color': 'red', 'points': 15}

aliens = [alien_0, alien_1, alien_2]

• A List in a Dictionary


pizza = {
'crust': 'thick',
'toppings': ['mushrooms', 'extra cheese'],
}

print("You ordered a " + pizza['crust'] +
"-crust pizza with " + pizza['toppings'])

#output
You ordered a thick-crust pizza with extra cheese.

• A List in a Dictionary

• 
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
print("Sarah's favorite language is " +
favorite_languages['sarah'].title())

#output
Sarah's favorite language is C

• You can nest a list inside a dictionary any time you want more than one value to be associated with a single key in a dictionary


favorite_languages = {
'jen': ['python', 'ruby'],
'sarah': ['c'],
'edward': ['ruby', 'go'],
}
print("Jen's favorite language is " +
favorite_languages['jen'].title())

#output
Sarah's favorite language is Python

• A Dictionary in a Dictionary


users = {
'aeinstein': {
'first': 'albert',
'last': 'einstein',
'location': 'princeton',
},

'mcurie': {
'first': 'marie',
'last': 'curie',
'location': 'paris',
},
}


full_name = users['aeinstein']['first'] +
" " + users['aeinstein']['last']
location = users['aeinstein']['location']

print("Full name: " + full_name.title())
print("Location: " + location.title())


#output
Full name: Albert Einstein
Location: Princeton


### Dictionaries: Summary

• Elements are key-value pairs. Empty dictionary {}

• Features：unpredictable order, key-value pairs are mutable (keys are immutable, but you can modify values). Do not make repeated keys.

• in operator works on keys (but you can use .values())

• Nesting: A list of dictionaries, a list in a dictionary, a dictionary in a dictionary

## 4.2 Tuples

• A tuple is a sequence of values much like a list. The important difference is that tuples are immutable

• The empty tuple can be written as tuple().

• 
>>> t = () #Empty is False
>>> print(t)
()

>>> t = ('a', 'b', 'c', 'd', 'e')

• To create a tuple with a single element, you have to include the final comma:


>>> t1 = ('a',)
>>> type(t1)
tuple

>>> t2 = ('a')
>>> type(t2)
str

• Most list operators also work on tuples. The bracket operator indexes an element:


>>> t = ('a', 'b', 'c', 'd', 'e')
>>> print(t)
'a'

>>> print(t[1:3])
('b', 'c')

>>> print('a' in t) # in operator

• You can't modify the elements of a tuple, but you can replace one tuple with another:


>>> t = 'A'
TypeError: object doesn't support item assignment
>>> t = ('A',) + t[1:]
>>> print(t)
('A', 'b', 'c', 'd', 'e')

• If you want to modify a tuple, you can convert it to a list, and then convert it back.


>>> t = (1,2,3)
>>> s = list(t) # s = [1,2,3]
>>> s.pop()
>>> t = tuple(s) # t = (1,2)

• Tuple assignment


>>> m = [ 'have', 'fun' ]
>>> (x, y) = m
>>> x
'have'
>>> y
'fun'



>>> m = [ 'have', 'fun' ]
>>> x, y = m
>>> x
'have'
>>> y
'fun'
>>> a, b = b, a #swap

• Lists and Tuples

• Lists can be in a tuple, and tuples can be in a list.


>>> s = [('a', 'b'), ('A', 'B')]
>>> t = ('a', 'b', ['A', 'B'])
>>> t = 'X'
>>> t = 'Y'
>>> t
('a', 'b', ['X', 'Y'])


>>> t = ('a', 'b', ['A', 'B'])
>>> t = ['X', 'Y']

Traceback (most recent call last):
File "test.py", line 2, in
t = ['X', 'Y']
TypeError: 'tuple' object does not support item assignment


>>> t = ('a', 'b', ('A', 'B'))
>>> t = 'X'

Traceback (most recent call last):
File "test.py", line 2, in
t = 'X'
TypeError: 'tuple' object does not support item assignment

• Dictionaries and tuples


>>> d = {'a':10, 'b':1, 'c':22}
>>> t = list(d.items())
>>> t
[('b', 1), ('a', 10), ('c', 22)]

• Using tuples as keys in dictionaries


>>> directory = dict()
>>> directory[('Taylor', 'Swift')] = 100
>>> print(directory)

{('Taylor', 'Swift'): 100}


### Tuples: Summary

• The element can be any type. The empty is ().

• Features: Ordered, Immutable, Repeatable

• Index and slice are the same with that of lists.

• You cannot modify the elements of a tuple, but you can replace one tuple with another.

• Multiple assignment with tuples.

• Tuples can be keys of a dictionary.

## 4.3 List, dictionary, tuple

### Comparison

Empty Feature
List [], list() ordered; mutable; repeatable
Tuple (), tuple() ordered; immutable; repeatable
Dictionary {}, dict() not ordered; key-value pairs and values are mutable, keys are not; values are repeatable, keys are not

### Mutable and Immutable

• Values are immutable. Thus, numbers, strings, tuples are immutable. Lists, dictionaries are mutable.

• What does it mean for immutable or mutable? What is assignment?

• variable $\rightarrow$ computer memory $\rightarrow$ object

• Assignment: The same immutable object occupies a single place in the memory even if you assign it to different variables. Every mutable object occupies different places in the memory even if the same objects are assigned to the same variable.

• Modify: When you modify the immutable object, you change the address in the memory. When you modify the mutable object, you do not change the address.


>>> x = 1
>>> id(x)
31106520
>>> y = 1
>>> id(y)
31106520
>>> x = 2
>>> id(x)
31106508
>>> y = 2
>>> id(y)
31106508
>>> z = y
>>> id(z)
31106508
>>> x+=2 #or x=x+2
>>> id(x)
31106484


>>> a = [1, 2, 3]
>>> id(a)
41568816
>>> a = [1, 2, 3]
>>> id(a)
41575088
>>> a.append(4)
>>> id(a)
41575088
>>> a+=
>>> id(a)
41575088
>>> a
[1, 2, 3, 4, 2]

>>> a=a+
>>> id(a)
41575596
>>> a
[1, 2, 3, 4, 2]


Be careful!

x = x + [] is assignment.

x + = [] is modification.


>>> a = [1, 2, 3]
>>> b = a
>>> id(a)
4476686208
>>> id(b)
4476686208
>>> a = a + [4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3]
>>> id(a)
4477187640
>>> id(b)
4476686208



>>> a = [1, 2, 3]
>>> b = a
>>> id(a)
4477149984
>>> id(b)
4477149984
>>> a+=[4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3, 4, 5, 6]
>>> id(a)
4477149984
>>> id(b)
4477149984


## 4.4 Functions Basics

• A function is a named sequence of statements that performs a computation.

• Build-in Functions

int(), float(), str(), type() and etc.

• To make your own functions, two steps: 1. define a function 2. call a function

• 
def lyrics():
print("I'm okay.")

lyrics()

• The first line of the function is called the header. The rest is called the body.You can use it inside another function

• 
def repeat_lyrics():
lyrics()
lyrics()

repeat_lyrics()

#output
I'm okay.
I'm okay.


### Parameters and arguments


def print_twice(bruce):
print(bruce)
print(bruce)


>>> print_twice('Spam')
Spam
Spam
>>> print_twice(17)
17
17


>>> michael = 'Eric, the half a bee.'
>>> print_twice(michael)
Eric, the half a bee.
Eric, the half a bee.


### Multiple parameters

• Positional Arguments


def describe_pet(type, name):
print("My " + type + "'s name is "
+ name.title() + ".")

describe_pet('hamster', 'harry')
describe_pet('dog', 'willie')

#output
My hamster's name is Harry.
My dog's name is Willie.

• Order Matters in Positional Arguments


describe_pet('harry', 'hamster')

#output
My harry's name is Hamster.

• Keyword Arguments


def describe_pet(type, name):
print("My " + type + "'s name is "
+ name.title() + ".")

describe_pet(type='hamster', name='harry')


describe_pet(type='hamster', name='harry')
describe_pet(name='harry', type='hamster')

• Default Values


def describe_pet(name, type='dog'):
print("My " + type + "'s name is "
+ name.title() + ".")

describe_pet(name='willie')

#output
My dog's name is Willie.


describe_pet(name='harry', type='hamster')
#The default value has been ignored.

• The following function calls have the same output.


# A dog named Willie.
describe_pet('willie')
describe_pet(name='willie')

# A hamster named Harry.
describe_pet('harry', 'hamster')
describe_pet(name='harry', type='hamster')
describe_pet(type='hamster', name='harry')

• Making an Argument Optional


def show_name(first, middle, last):
full_name = first + ' ' + middle + ' ' + last
print(full_name.title())

show_name('john', 'lee', 'hooker')


def show_name(first, last, middle=''):
if middle:
full_name = first + ' ' + middle + ' ' + last
else:
full_name = first + ' ' + last
print(full_name.title())

show_name('jimi', 'hendrix')


### Fruitful functions and void functions

• Some of the functions yield results, fruitful fucntions

Some of the functions do not return a value, void fucntions

• To return a result from a function, we use the return statement in our function.

• 
# if only return, then it will return None.

print(x)



print(x)

#output
None

• Return and Print



print(x)

#output
8
None



print(x)

#output
8
8

• If we want to return multiple values, the function return a tuple.



print(x)

#output
(3, 5, 8)

• A function can return any kind of value you need it to, including more complicated data structures like lists and dictionaries.


def build_person(first_name, last_name):
person = {'first': first_name, 'last': last_name}
return person

musician = build_person('jimi', 'hendrix')
print(musician)

#output
{'first': 'jimi', 'last': 'hendrix'}

##### mutable vs. immutable
• For immutable objects (number, string, tuple), the assignment inside a function cannot change the value of the variable outside the function even if the variable name inside is the same with the variable name outside.


def ChangeInt(a):
a = 10

b = 2
ChangeInt(b)
print(b)

#output
2

############################
def ChangeInt(b):
b = 10

b = 2
ChangeInt(b)
print(b)

#output
2


### Examples


def ChangeInt(a):
a = 10
print(a)
return a

b = 2
ChangeInt(b)
print(b)
print(ChangeInt(b))

10
2
10
10

• For mutable objects (list, dictionary), the assignment inside a function cannot change the value of the variable outside the function. (the same with immutable objects!)


def changeme(mylist):
mylist = [1,2]
print("inside: ", mylist)

x = [10,20]
changeme(x)
print("outside: ", x)

#output
inside:  [1, 2]
outside:  [10, 20]


• However, the modification can change the value of the variable outside.


def changeme(mylist):
mylist.extend([1,2])
print ("inside: ", mylist)

x = [10,20]
changeme(x)
print ("outside: ", x)

#output
inside:  [10, 20, 1, 2]
outside:  [10, 20, 1, 2]


## Reminder: Pac-man game

Pac-man game

http://www.webpacman.com/

## Summary

• Dictionaries, tuples
• Mutable and immutable
• Function Basics