BPLCK105B Module 2 Notes
BPLCK105B Module 2 Notes
Module 2
Lists: The List Data Type, Working with Lists, Augmented Assignment Operators, Methods,
Example Program: Magic 8 Ball with a List, List-like Types: Strings and Tuples, References.
Dictionaries and Structuring Data: The Dictionary Data Type, Pretty Printing, Using Data
Structures to Model Real-World Things
Textbook 1: Al Sweigart, “Automate the Boring Stuff with Python”, 1st Edition, No Starch Press,
2015. (Available under CC-BY-NC-SA license at https://automatetheboringstuff.com/)
print(L3) #displays [ ]
print(spam) #displays ['cat', 'bat', 'rat', 'elephant']
• Lists can also contain other list values. The values in these lists of lists can be accessed using
multiple indexes.
• The first index dictates which list value to use, and the second indicates the value within the list
value.
>>> spam = [['cat', 'bat'], [10, 20, 30, 40, 50]]
>>> spam #[['cat', 'bat'], [10, 20, 30, 40, 50]]
>>> spam[0][1] #'bat'
>>> spam[1][4] #50
>>> spam[2][0] #IndexError: list index out of range
>>> spam[1][5] #Index Error
Negative Indexes
• Indexes start at 0 and go up, we can also use negative integers for the index.
• The integer value -1 refers to the last index in a list, the value -2 refers to the second-to-last index in
a list, and so on.
>>> spam = ['cat', 'bat', 'rat', 'elephant']
>>> spam[-1] #'elephant'
>>> spam[-3] #'bat'
>>> spam[3] #elephant
• Indexes start at 0 and go up, we can also use negative integers for the index.
• The integer value -1 refers to the last index in a list, the value -2 refers to the
second-to-last index in a list, and so on.
>>> spam = ['cat', 'bat', 'rat', 'elephant']
>>> spam[-1] #'elephant'
>>> spam[-3] #'bat'
>>> 'The ' + spam[-1] + ' is afraid of the ' + spam[-3] + '.‘
#'The elephant is afraid of the bat.'
We can leave out one or both of the indexes on either side of the colon in the slice.
Leaving out the first index is the same as using 0 and Leaving out the second index is same as
using the length of the list.
>>> spam = ['cat', 'bat', 'rat', 'elephant']
>>> spam[:2] #['cat', 'bat'] prints elements of pos 0 and 1
>>> spam[1:] #['bat', 'rat', 'elephant'] prints all excluding 0
>>> spam[:] #['cat', 'bat', 'rat', 'elephant'] prints all
The + operator can combine two lists to create a new list value in the same way it combines two
strings into a new string value.
The * operator can also be used with a list and an integer value to replicate the list.
>>> [1, 2, 3] + ['A', 'B', 'C'] #[1, 2, 3, 'A', 'B', 'C']
>>> ['X', 'Y', 'Z'] * 3 #['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', 'Z']
>>> spam = [1, 2, 3]
>>> spam = spam + ['A', 'B', 'C']
>>> spam #[1, 2, 3, 'A', 'B', 'C']
Output:
Enter name of cat1or q to stop: candy
The cat names are: candy
Enter name of cat2or q to stop: arjun
The cat names are: candy arjun
Enter name of cat3or q to stop: q
The number of variables and the length of the list must be exactly equal, or Python will give you
a ValueError:
>>> size, color, disposition, name = cat
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
size, color, disposition, name = cat
ValueError: not enough values to unpack (expected 4, got 3)
The += operator can also do string and list concatenation, and the *= operator can do string and
list replication.
>>> fruits='Apple'
>>> fruits+=' Banana'
>>> fruits+=' Mango'
>>> fruits #'Apple Banana Mango‘
>>> fruits=['Apple']
>>> fruits *=3 #fruits*3
>>> fruits #['Apple', 'Apple', 'Apple']
2.4. Methods
Methods: Finding a Value in a List with the index() Method
A method is the same thing as a function, except it is “called on” a value.
Each data type has its own set of methods.
List values have an index() method that can be passed a value, and if that value exists in the list,
the index of the value is returned. If the value isn’t in the list, then Python produces a ValueError
error.
>>> spam = ['hello', 'hi', 'how', 'are','you']
>>> spam.index('hello') #0
>>> spam.index('how') #2
>>> spam.index('hello hi') #'hello hi' is not in list
When there are duplicates of the value in the list, the index of its first appearance is returned.
>>> spam = ['hello', 'hi', 'how', 'are','hello','you']
>>> spam.index('hello') #0
The append() and insert() methods are list methods and can be called only on list values, not on
other values such as strings or integers.
Attempting to delete a value that does not exist in the list will result in a ValueError error.
>>> fruits=['Apple', 'Grapes', 'Mango', 'Orange']
>>> fruits.remove('Pineapple') #ValueError: list.remove(x): x not in list
If the value appears multiple times in the list, only the first instance of the value will be removed.
>>> fruits=['Apple', 'Grapes','Apple', 'Grapes', 'Mango', 'Orange']
>>> fruits #['Apple', 'Grapes', 'Apple', 'Grapes', 'Mango', 'Orange']
>>> fruits.remove('Grapes')
sort() function cannot sort lists that have both number values and string values in them, since
Python doesn’t know how to compare these values.
>>> spam = [1, 3, 2, 4, 'Alice', 'Bob']
>>> spam.sort() #TypeError: '<' not supported between instances of 'str' and 'int'
sort() uses “ASCIIbetical order” rather than actual alphabetical order for sorting
strings. This means uppercase letters come before lowercase letters. Therefore,
the lowercase a is sorted so that it comes after the uppercase Z.
If you need to sort the values in regular alphabetical order, pass str. lower for the key keyword
argument in the sort() method call.
>>> spam = ['a', 'z', 'A', 'Z']
>>> spam.sort(key=str.lower)
>>> spam #['a', 'A', 'z', 'Z']
When you run this program, you’ll see that it works the same as the previous magic8Ball.py
program.
Notice the expression you use as the index into messages: random.randint(0, len(messages) - 1).
This produces a random number to use for the index, regardless of the size of messages. That is,
you’ll get a random number between 0 and the value of len(messages) - 1.
The benefit of this approach is that you can easily add and remove strings to the messages list
without changing other lines of code.
If you later update your code, there will be fewer lines you have to change and fewer chances for
you to introduce bugs.
Output
Very doubtful
Concentrate and ask again
My reply is no
Example
>>> name='Apple‘
>>> name[0] #'A'
>>> name[-2] #'l'
>>> name[0:4] #'Appl'
>>> 'Ap' in name #True
>>> 'p' not in name #False
>>> for i in name:
print('* * *' + i + '* * *')
Output
* * *A* * *
* * *p* * *
* * *p* * *
* * *l* * *
* * *e* * *
List is Mutable
>>> eggs=[1,2,3]
>>> eggs #[1, 2, 3]
>>> eggs=[4,5,6]
>>> eggs #[4, 5, 6]
The list value in eggs isn’t being changed here; rather, an entirely new and different list value ([4,
5, 6]) is overwriting the old list value ([1, 2, 3]).
>>> eggs1=(2)
>>> eggs1 #2
>>> type(eggs1) #<class 'int'>
>>> type(('hello')) #<class 'str'>
>>> eggs2=(2,)
>>> eggs2 #(2,)
>>> type(eggs2) #<class 'tuple'>
>>> type(('hello',)) #<class 'tuple'>
>>> list3=list('hello')
>>> list3 #['h', 'e', 'l', 'l', 'o']
2.7. References
Variables store strings and integer values
>>> spam=42
>>> cheese=spam
>>> spam=100
>>> spam #100
>>> cheese #42
When you assign a list to a variable, you are actually assigning a list reference to the variable. A
reference is a value that points to some bit of data, and a list reference is a value that points to a
list.
>>> spam = [0, 1, 2, 3, 4, 5]
>>> cheese = spam
>>> cheese[1] = 'Hello!'
>>> cheese #[0, 'Hello!', 2, 3, 4, 5]
>>> spam #[0, 'Hello!', 2, 3, 4, 5]
Passing References
References are particularly important for understanding how arguments get passed to functions. When a
function is called, the values of the arguments are copied to the parameter variables.
def eggs(Param):
Param.append('Hello')
spam = [1, 2, 3]
eggs(spam)
If the function modifies the list or dictionary that is passed, these changes will affect the original
list or dictionary value.
For this, Python provides a module named copy that provides both the copy() and deepcopy()
functions.
copy.copy(), can be used to make a duplicate copy of a mutable value like a list or dictionary, not
just a copy of a reference.
Deep copy is a process in which the copying process occurs recursively. In case of deep copy, a
copy of object is copied in other object.
Any changes made to a copy of object do not reflect in the original object. In python, this is
implemented using “deepcopy()” function.
print(d)
or
LIST DICTIONARY
List is a collection of index values pairs as that Dictionary is a hashed structure of key and
of array in c++. value pairs.
The indices of list are integers starting from 0. The keys of dictionary can be of any data type.
The elements are accessed via indices. The elements are accessed via key-values.
Items in dictionaries are unordered. First element in the list would be at index 0. But, no first
item in dictionary. Dictionaries are not ordered, they can’t be sliced like lists.
>>> spam = ['cats', 'dogs', 'moose']
>>> bacon = ['dogs', 'moose', 'cats']
>>> spam == bacon #False
>>> eggs = {'name': 'Zophie', 'species': 'cat', 'age': '8'}
>>> ham = {'species': 'cat', 'age': '8', 'name': 'Zophie'}
>>> eggs == ham
Though dictionaries are not ordered, the fact that you can have arbitrary values for the keys allows
you to organize your data in powerful ways. Example: program to store data about birthdays using
a dictionary with the names as keys and the birthdays as values.
birthdays = {'Raju': 'Apr 19', 'Manu': 'Jul 12', 'Anup': 'Jul 9'}
while True:
print('Enter a name: (blank to quit)')
name = input()
if name == '':
break
if name in birthdays:
print(birthdays[name] + ' is the birthday of ' + name)
else:
print('I do not have birthday information for ' + name)
print('What is their birthday?')
bday = input()
birthdays[name] = bday
print('Birthday database updated.')
A for loop can also iterate over the keys or both keys and values:
spam = {'color': 'red', 'age': 42}
for k in spam.keys():
print(spam[k]) # red 42
for i in spam.items():
print(i) #('color', 'red') ('age', 42)
Using the keys(), values(), and items() methods, a for loop can iterate over the keys, values, or
key-value pairs in a dictionary. The values in the dict_items value returned by the items() method
are tuples of the key and value.
spam = {'color': 'red', 'age': 42}
for k in spam.keys():
print(spam[k]) # red 42
for i in spam.items():
print(i) #('color', 'red') ('age', 42)
The get() method returns the value of the item with the specified key.
Syntax: dictionaryname.get(keyname, value)
Parameter Values
Keyname Required The keyname of the item you want to return the value from
value Optional A value to return if the specified key does not exist. Default value
None
Output: 'I bought toyota car etios liva model in the year 2011‘
If no key in the dictionary, the default value 0 is returned by the get() method. If no get method is
used and no key present in dictionary, then ERROR will be raised.
>>> car={'brand': 'toyota', 'model': 'etios liva', 'year': 2011}
>>> I bought '+str(car['brand']) + ' color: ' + str(car['color'])
Output: KeyError: 'color'
General Way
fruits = {'name': 'Apple', 'cost': 90}
if 'color' not in fruits:
fruits['color'] = 'green'
print(fruits)
Using setdeault
fruits = {'name': 'Apple', 'cost': 90}
fruits.setdefault('color', 'black')
print(fruits)
Using setdeault
fruits = {'name': 'Apple', 'cost': 90,'color': 'Red'}
print(fruits)
fruits.setdefault('color', 'green')
print(fruits)
The setdefault() method is a nice shortcut to ensure that a key exists. Here is a short program that
counts the number of occurrences of each letter in a string.
Example
message = 'Application Development using Python Programming'
count = {}
for character in message:
count.setdefault(character, 0)
count[character] = count[character] + 1
print(count)
#{'A': 1, 'p': 3, 'l': 2, 'i': 4, 'c': 1, 'a': 2, 't': 3, 'o': 4, 'n': 5, ' ': 4, 'D': 1, 'e': 3, 'v': 1, 'm': 3, 'u': 1, 's': 1,
'g': 3, 'P': 2, 'y': 1, 'h': 1, 'r': 2}
The program loops over each character in the message variable’s string, counting how often each
character appears. The setdefault() method call ensures that the key is in the count dictionary (with
a default value of 0) so the program doesn’t throw a KeyError error when count[character] =
count[character] + 1 is executed.
count[character] = count[character] + 1
pprint.pprint(count)
The pprint.pprint() function is especially helpful when the dictionary itself contains nested lists or
dictionaries.
A Tic-Tac-Toe Board
A tic-tac-toe board looks like a large hash symbol (#) with nine slots that can each contain an X,
an O, or a blank.
To represent the board with a dictionary, you can assign each slot a string-value key. String values
'X', 'O', or ' ' (a space character) are used in each slot on the board which needs to store nine strings.
So, dictionary can be used. The string value with the key 'top-R' can represent the top-right corner,
the string value with the key 'low-L' can represent the bottom-left corner, the string value with the
key 'mid-M' can represent the middle, and so on.
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': '
', 'low-M': ' ', 'low-R': ' '}
theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O', 'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ','low-
L': ' ', 'low-M': ' ', 'low-R': 'X'}
Player O wins
printBoard(theBoard)
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-
M': ' ', 'low-R': ' '}
def printBoard(board):
print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
turn = 'X'
for i in range(9):
printBoard(theBoard)
print('Turn for ' + turn + '. Move on which space?')
move = input()
theBoard[move] = turn
if turn == 'X':
turn = 'O'
else:
turn = 'X'
printBoard(theBoard)
for x in d:
print(x) # brand model year
You can also use the values() function to return values of a dictionary:
for x in d.values():
print(x) # Toyota etios liva 2018
To determine how many items (key-value pairs) a dictionary has, use the len() method.
Example: Print the number of items in the dictionary:
d = { "brand": "toyota", "model": "etios liva", "year": 2011 }
print(len(d))
Adding an item to the dictionary is done by using a new index key and assigning a value to it:
d = { "brand": "toyota", "model": "etios liva", "year": 2011 }
d["color"] = "White"
print(d)
#{'brand': 'Toyota', 'model': 'Etios liva', 'year': 2011, 'color': 'White'}
Copy a Dictionary
Cannot copy a dictionary using dict2 = dict1, because: dict2 will only be a reference to dict1, and
changes made in dict1 will automatically reflects in dict2.
To make a copy, use the built-in Dictionary method copy().
d = {"brand": "toyota", "model": "etios liva", "year": 2011 }
myd = d.copy()
print(myd)
# {'brand': 'Toyota', 'model': 'Etios liva', 'year': 2011}
if c not in d:
d[c] = 1
else:
d[c] = d[c] + 1
print(d)
# {'W': 1, 'e': 2, 'l': 1, 'c': 1, 'o': 1, 'm': 1}
Dictionaries have a method called “get” that takes a key and a default value. If the key appears in
the dictionary, get returns the corresponding value; otherwise it returns the default value.
For example:
d = {"brand": "toyota", "model": "etios liva", "year": 2011 }
print(d.get('year', 0)) #or print(d.get('year')) #2011
print(d.get('color', 0)) #0
print(d.get('color', 'white')) #white
The get method automatically handles the case where a key is not in a dictionary, we can reduce
four lines down to one and eliminate the if statement.
word = 'welcome'
d = dict()
for c in word:
d[c] = d.get(c,0) + 1
print(d) # {'w': 1, 'e': 2, 'l': 1, 'c': 1, 'o': 1, 'm': 1}
If you use a dictionary as the sequence in a for statement, it traverses the keys of the dictionary.
This loop prints each key and the corresponding value:
d = {"brand": "Toyota", "model": "Etios liva", "year": 2011}
for key in d:
print(key, d[key]) #brand Toyota model Etios liva year 2011
Example: if we wanted to find all the entries in a dictionary with a value above ten, we could
write the following code:
counts = { 'chuck' : 1 , 'annie' : 42, 'jan': 100}
for key in counts:
if counts[key] > 10 :
print(key, counts[key]) # annie 42 jan 100