For full screen view & to download, visit

To go back to ML website, Click here

Introduction

We have to learn some basic programming concepts before doing anything in Maching Learning or Data Science or any Projects.

This notebook is created on the presumption that you have some basic grounding on programming world, with some idea on variables & data types, arrays, flow conditions - if | else | elif | while | for | break | continue, importing libraries & functions, Functions - creating functions | passing arguments | returning values.

TIP: Visit Python Tutor Visualizer to visualise the code and understand what happens in the behind the screen when each line of Python code runs.

Python Basics

Entering expressions

In [1]:
2+2
Out[1]:
4

Commonly used math operators

  • Addition
  • Subtraction
  • Multiplication
  • Division
  • Integer Division
  • Moduls/ Remainder
  • Exponent/ Power

Order of Precedence

The order of operations (also called precedence) of Python math operators is similar to that of mathematics. The * operator is evaluated first; the , /, //, and % operators are evaluated next, from left to right; and the + and - operators are evaluated last (also from left to right)

In [15]:
2+3*6
Out[15]:
20
In [16]:
(2 + 3) * 6
Out[16]:
30
In [17]:
2**5
Out[17]:
32
In [25]:
22/7
Out[25]:
3.142857142857143
In [26]:
22//7
Out[26]:
3
In [27]:
22 % 7
Out[27]:
1

Common data types

Common Data Types

  • Integer - int
    • e.g. 0,50,-100
  • Floating-Point - float
    • e.g. 1.25, 3.14, -1.0, --0.5, 0.0
  • String - str
    • e.g. 'a', 'aa', 'aaa', 'Hello!', '11 cats'
  • Boolean - bool
    • e.g. True, False

String can be enclosed in single or double quotes

String concatenation & Replicaiton

The meaning of an operator (e.g. +) may change based on the data types of the values next to it

In [23]:
# Addition for int or float
1 + 2
Out[23]:
3
In [22]:
# Concatenation for string data type
'Bruce' + 'Wayne'
Out[22]:
'BruceWayne'

If you try to use the + operator on a string and an integer value, Python will not know how to handle this, and it will display an error message

.

In [29]:
'Bruce' + 42
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-29-ec44728c2272> in <module>()
      1 # if you try to use the + operator on a string and an integer value,
      2 # Python will not know how to handle this, and it will display an error message.
----> 3 'Bruce' + 42

TypeError: must be str, not int

The * operator when used on one string value and one integer value becomes string replication operator.

In [31]:
2*5
Out[31]:
10
In [30]:
'Batman'*5
Out[30]:
'BatmanBatmanBatmanBatmanBatman'

Varaibles

  • It's like box in the computer’s memory where we can store values

Variable Names are case sensitive.
We can name a variable anything as long as it obeys the following three rules:

  • It can be only one word.
  • It can use only letters, numbers, and the underscore _ character.
  • It can’t begin with a number.

e.g. of invalid variable names:
current-balance, current balance 4account, total_$um, 'batman'

Hello world - First Python program

In [4]:
# This program says hello and asks for my name.

print('Hello world!')
print('What is your name?')    # ask for their name
myName = input()
print('It is good to meet you, ' + myName)
print('The length of your name is:')
print(len(myName))
print('What is your age?')    # ask for their age
myAge = input()
print (type(myAge))
print('You will be ' + str(int(myAge) + 1) + ' in a year.')
Hello world!
What is your name?
James Bond
It is good to meet you, James Bond
The length of your name is:
10
What is your age?
50
<class 'str'>
You will be 51 in a year.

Program Breakdown

Comments

The following line is called a comment. Python ignores comments, and you can use them to write notes or remind yourself what the code is trying to do. Any text for the rest of the line following a hash mark # is part of a comment.

In [5]:
# This program says hello and asks for my name.

To comment across multiple lies, we can use triple quotes (could be single ''' or double """)

In [193]:
'''This line is part of multine comment

This line is also part of multiline comment

Again, this line as well is a multiline comment'''

print ('Hello')
Hello

print() function

The print() function displays the string value inside the parentheses on the screen. Notice that the quotes are not printed to the screen. They just mark where the string begins and ends; they are not part of the string value.

In [6]:
print('Hello world!')
print('What is your name?')    # ask for their name
Hello world!
What is your name?

input() function

The input() function waits for the user to type some text on the keyboard and press ENTER key. The user input will then be stored in myName variable

In [7]:
myName = input()
Gandolf the Gray

The expression 'It is good to meet you, ' + myName is evaluated and is printed on the screen.

In [8]:
print('It is good to meet you, ' + myName)
It is good to meet you, Gandolf the Gray

len() function

The len() function returns the number of characters in the given string.

In [9]:
print('The length of your name is:')
print(len(myName))
The length of your name is:
16

type() function

The type() function returns the data type of the value given

In [7]:
print('What is your age?')    # ask for their age
myAge = input()
print (type(myAge))           # the input functions usually returns a string data type
What is your age?
50
<class 'str'>

str(), int(), float() functions

These functions are used to change the data types of the values.
As the input() function returns str data, myAge variable is of str data type.
To add a numerical value to it, the value should be converted to int.
After performing the addition, the int value is converted back to str again so that it can be concatenated with other strings.

In [8]:
print('You will be ' + str(int(myAge) + 1) + ' in a year.')
50

Flow Control

and,or,not and <,>,<=,>=,==,!=

  • Boolean Values: True, False
  • Boolean operators: and,or,not
    • returns True or False
  • Comparison operators: <, >, <=, >=, ==, !=
    • returns True or False
In [14]:
5 > 6
Out[14]:
(False, True, False)
In [20]:
5 <= 6, 3>5, 3!=5, 3 == 5
Out[20]:
(True, False, True, False)
In [17]:
5<6 and 3>5, 5<6 or 3>5
Out[17]:
(False, True)
In [12]:
not (True), not(False)
Out[12]:
(False, True)

Flow control

if,else,elif

if

  • When if condition evalues to True, the block of statement indented inside will get executed.
  • The block can be indented (pushed in) by Tab. The block can be deindented by Shift+Tab

Note: There should be atleast one line of indented code after if condition

In [30]:
age = 5
if age < 10:                       # age < 10 evaluates to True      
    print ('age is less than 10')  # if True, this code will get executed
age is less than 10
In [31]:
age = 15
if age < 10:                       # age < 10 evaluates to False             
    print ('age is less than 10')  # Doesn't get printed as age variable us more than 10

else

  • When if condition evalues to True, the block of statement indented inside if will get executed.
  • When it evaluates to False, the block of statement indented inside else will get executed.
In [32]:
age = 18
if age < 18:                     
    print ('You are not an adult')
else:
    print ('You are an adult')
You are an adult

elif

  • When if condition evalues to True, the block of statement indented inside if will get executed.
  • When it fails, the elif condition will be evaluated and if it turns out to be True, the block of statement indented inside elif will get executed.
  • When both if and elif evaluates to False, the block of statement indented inside else will get executed.
In [37]:
age = 10
if age > 18:
    print ('You are  an adult')
elif age > 12:
    print ('You are a teenager')
else:
    print ('You are neither adult nor teen. Just a kid!')
You are neither adult nor teen. Just a kid!

We can have multiple elif statements after an if statement. In the entire combo, if-elseif-else combo, only one of the condition will be exeucted. The order of execution is from top to bottom.

In [41]:
age = 15
if age >60 :
    print ('You are very old')
elif age>18:
    print ('You are an adult')
elif age > 12:
    print ('You are a teenager')
else:
    print ('You are neither adult nor teen. Just a kid!')
You are a teenager

nested if

We can have if-else inside another if-else and we can keep nesting them. The deeper the nest gets, the harder it will be to debug and trace.

In [44]:
user_name = input('Enter user name: ')      # james bond
pass_word = input('Enter pass word: ')      # 007
if user_name == 'james bond':
    if pass_word == '007':
        print ('Access granted')
    else:
        print ('Access denied. Wrong password')
else:
     print ('Access denied. Wrong username')
Enter user name: james bond
Enter pass word: 008
Access denied. Wrong password

The above code could be re-witten as follows using boolean and comparison operators making it easy to read and follow

In [46]:
user_name = input('Enter user name: ')      # james bond
pass_word = input('Enter pass word: ')      # 007
if user_name == 'james bond' and pass_word == '007':
    print ('Access granted')
else:
    print ('Access denied. Wrong login details')
Enter user name: james bond
Enter pass word: 007
Access granted

Loops

while loop

  • while loop keeps on running as long as the condition evaluates to True
In [1]:
i = 10
print ('Loop start')
while i>0:            # while loop evaluates to true as long as i>0
    print (i)
    i = i - 1         # everytime, the loop runs, value of `i` decreases by 1
print ('Loop end')    # This line of code is outside the loop. Will run only when the while loop ends
Loop start
10
9
8
7
6
5
4
3
2
1
Loop end

What happens if you run while False: and while True:?

for loop

  • for loop runs for a fixed number of iterations.
  • Here, the range(10) returns a list of numbers from 0 to 9.
  • Everytime, the for loop runs, the iterator variable i takes the next available value from the list.
In [3]:
for i in range(10):
    print (i)
0
1
2
3
4
5
6
7
8
9
  • Beside using range() function in for loop, we can use many other data types.
  • Here, I have used list type containing list of 4 names and used for loop to read through all names in list, one at a time .

Note: We will see more about list data types later.

In [5]:
for name in ['Batman', 'Superman', 'Ironman', 'Thanos']:
    print (name)
Batman
Superman
Ironman
Thanos
  • We can also loop through each element in a string data type

Note: We will see more about string data types later.

In [6]:
for letter in 'Bruce Wayne':
    print (letter)
B
r
u
c
e
 
W
a
y
n
e

break

break is used to exit the loop (while or for) the program is currently evaluating prematurely based on certain conditions.

In [9]:
print ('Loop start')
for letter in 'Bruce Wayne':
    print (letter)
    if letter == 'e':
        print ('Break the loop')
        break                     # this command breaks the for loop (takes the program outside the loop)
print ('Loop end')
Loop start
B
r
u
c
e
Break the loop
Loop end

continue

  • continue is used to skip the execution of code inside the loop (for or while) and move on to next iteration on certain conditions.

The program below skips printing the vowel letters and prints the rest of the consonants.

In [11]:
print ('Loop start')
for letter in 'Bruce Wayne':
    if letter == 'a' or letter =='e' or letter =='i' or letter =='o' or letter =='u':
        continue      # this command skips lines inside the for loop below this line and starts the next iteration
    print (letter)
               
print ('Loop end')
Loop start
B
r
c
 
W
y
n
Loop end

in

  • The in operator can be used to check whether a value is inside another and it evaluates to bool (True,False)

Note: We will see more about in, str & list data types later.

In [14]:
'a' in 'James'
Out[14]:
True
In [20]:
'b' in 'James', 'Ja' in 'James', 'James' in 'James', 'JameS' in 'James'
Out[20]:
(False, True, True, False)
In [13]:
print ('Loop start')
for letter in 'Bruce Wayne':
    if letter in 'aeiou':          
        continue      # this command skips lines inside the for loop below this line and starts the next iteration
    print (letter)
               
print ('Loop end')
Loop start
B
r
c
 
W
y
n
Loop end

Functions

import

built-in functions

  • Till now, we have used a basic set of functions like print(), inpu()t, len(), str(), int(), float().

standard library

  • Set of modules that conatins related group of functions embedded together.
  • e.g.
    • math module contains mathematic related functions.
    • random module containsrandom number related functions.

Functions are often used as "Black Boxes". Often, all we need to know is its inputs (parameter values), outputs and its generic function. We don't have to burden to understand each and every function and the code inside it.

random library

In [24]:
import random                # Before using a function in standard library, we have to use import _______
print (random.randint(1,10)) # Randomly generates an integer from 1 to 10
5
In [23]:
print (random.randint(1,10))  # Randomly generates an integer from 1 to 10
1

math library

In [30]:
import math
math.sqrt(2)
Out[30]:
1.4142135623730951
In [31]:
math.pi
Out[31]:
3.141592653589793

Function - def

  • A function is like mini program inside a program.
  • The idea behind function is to avoid duplicating code.
  • Deduplicaiton makes our code shorter, easier to read and update.

fn - without arguments and return

In [47]:
# create a function named 'welcome'. It neither take any input and nor returns any output
def welcome():
    print ('hi')
    print ('mi casa es tu casa')
In [46]:
# invoking/ calling a function
welcome()
hi
mi casa es tu casa
In [43]:
welcome()
welcome()
hi
mi casa es tu casa
hi
mi casa es tu casa

fn - with arguments

In [51]:
def hello(name):
    print ('Hello ' + name + '!')
    print ('Bienvenido a casa')
In [52]:
hello('Scare Crow')
Hello Scare Crow!
Bienvenido a casa

fn - with return

  • e.g.
    • len() - returns the lenght of the argument passed inside
    • len('Python') >>> 5
In [54]:
def greet(lan):
    if lan == 'english':
        return 'Welcome'
    elif lan == 'spanish':
        return 'Bienvenido'
    elif lan == 'french':
        return 'Bonjour'
    else:
        return 'Welcome'
In [56]:
greet('english')
Out[56]:
'Welcome'
In [59]:
greet('french')
Out[59]:
'Bonjour'

Local and Global scope

  • Local scope - Variables inside the function exist in local scope

    • Created whenever a function is called
    • Variables created inside a function eist within local scope and they cannot be used outside the function
    • When the function returns/ ends, the scope is closed/ destroyed along with the variables inside it
    • The next time we call the function, the local scope is created again and they wont remember the previous values
  • Global scope - Variables that are assigned outside all functions exist in global scope

    • Created when our program begins
    • When program ends, the global scope is destroyed

A variable must be either in local or global scope, cannot be both.

Note: We will see more about Local and Global scope later.

Lists

We have already seen bool, int, float, str built-in data types.list is my personal favortie data type in Python . Two other cool built-in data types that we will explore in further sections are tuples and dict.

  • list will be very helpful to handle large amount of data and hierarchical structures.
  • str and tuple have lot of list like features which will also be in further sections below.
  • list can contain another list and many other different data types inside it.

List data type

  • Variable that contains multiple values in an ordered sequence
  • They start and end with [ ]
  • Values inside the list are called as items
In [64]:
animals = ['cat', 'bat', 'rat', 'cow', 'dog']
In [65]:
animals
Out[65]:
['cat', 'bat', 'rat', 'cow', 'dog']

List index

Getting individual values in a List with indices

  • The list index starts from 0
  • The index no can only be integers

To ponder : What happens when you try to access an element with index number that doesn't exist in the list? 🤔

In [66]:
animals[0]
Out[66]:
'cat'
In [67]:
animals[1]
Out[67]:
'bat'
In [68]:
animals[1.0]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-68-ac423d8e17b8> in <module>()
----> 1 animals[1.0]

TypeError: list indices must be integers or slices, not float
In [83]:
animals[-1]    # Go in reverse direction
Out[83]:
'rat'

Change list value using index

In [92]:
animals = ['cat', 'bat', 'rat', 'cow', 'dog']
In [93]:
animals
Out[93]:
['cat', 'bat', 'rat', 'cow', 'dog']
In [95]:
animals[1] = 'horse'     # Override the item in index 1 of list 
print (animals)
['cat', 'horse', 'rat', 'cow', 'dog']

List of List

In [76]:
num = [[1,2,3,4,5],[6,7,8,9,10]]
In [78]:
num[0]
Out[78]:
[1, 2, 3, 4, 5]
In [80]:
num[0][0]
Out[80]:
1
In [81]:
num[1][0]
Out[81]:
6

List slice

Syntax: list_name[start:stop(exclusive):jump] Default values

  • start = 0
  • stop = last item in list
  • jump = 1
In [71]:
animals = ['cat', 'bat', 'rat', 'cow', 'dog', 'rat']
animals[0:2]    # Returns list items from index = 0 to index = 2-1 
Out[71]:
['cat', 'bat']
In [72]:
animals[0:5:2]
Out[72]:
['cat', 'rat', 'dog']
In [84]:
animals[0:5:1]
Out[84]:
['cat', 'bat', 'rat', 'cow', 'dog']
In [87]:
animals[::]
Out[87]:
['cat', 'bat', 'rat', 'cow', 'dog', 'rat']
In [89]:
animals[::-1]   # Traverse in reverse direction
Out[89]:
['rat', 'dog', 'cow', 'rat', 'bat', 'cat']

for loop with list

In [91]:
animals = ['cat', 'bat', 'rat', 'cow', 'dog', 'rat']
for animal in animals:
    print (animal)
cat
bat
rat
cow
dog
rat

len()

In [96]:
animals = ['cat', 'bat', 'rat', 'cow', 'dog', 'rat']
len(animals)
Out[96]:
6

empty list

We can create empty list using [] notation or list() function.

In [9]:
# empty list
animals = []                            # or try # list()
print ('Data type =', type(animals))
print ('No of elements =', len(animals))
Data type = <class 'list'>
No of elements = 0

List concatenation

In [99]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
birds = ['crow', 'pigeon', 'sparrow']
In [100]:
animals + birds      # Joins the 2 list and returns a new list
Out[100]:
['cat', 'rat', 'cow', 'dog', 'rat', 'crow', 'pigeon', 'sparrow']

del

In [104]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
del animals[2]       # delete the list item at index 2
animals
Out[104]:
['cat', 'rat', 'dog', 'rat']

in & not in operators

In [106]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
print ('cat'in animals)
print ('crow' not in animals)
True
True

list methods

append()

  • Add Single Element to The end of the List
In [114]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
animals.append('Gorilla')
print (animals)
['cat', 'rat', 'cow', 'dog', 'rat', 'Gorilla']

insert()

  • Inserts element to the list in given index
In [115]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
animals.insert(2, 'Gorilla')
print (animals)
['cat', 'rat', 'Gorilla', 'cow', 'dog', 'rat']

remove()

  • searches for the given element in the list and removes the first matching element.
In [116]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
animals.remove('rat')
print (animals)
['cat', 'cow', 'dog', 'rat']

index()

  • searches for given element in the list and returns its index. If the same element is present more than once, index() method returns its smallest/first position.
In [117]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
print (animals.index('rat'))
1

reverse()

  • reverses the elements of a given list.
In [119]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
animals.reverse()
print (animals)
['rat', 'dog', 'cow', 'rat', 'cat']

sort()

  • sorts the elements of a given list in a specific order - Ascending or Descending.
In [120]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
animals.sort()
print (animals)
['cat', 'cow', 'dog', 'rat', 'rat']
In [121]:
animals.sort(reverse=True)
print (animals)
['rat', 'rat', 'dog', 'cow', 'cat']

count()

  • the number of times given element appears in the list.
In [125]:
animals = ['cat', 'rat', 'cow', 'dog', 'rat']
print (animals.count('rat'))
2

For more details on list, visit the Python documentation or Python List Methods.

Tuples

tuple data type

The tuple data type is identicial to list data type, except in 2 ways

  1. Tuples are identified with paranetheses ( and ) whereas lists are identified by sqaure brackets [ and ]
  2. Tuples are immutable
    • Tuples cannot have their values modified, removed or appended

If you have only one value in the tuple, indicate that by adding a trailing comma after the value inside

  • e.g. ('hello',) is a tuple with only one value
In [128]:
tuple_1 = ('easter_eggs', 1, 3.14)
print (tuple_1)
('easter_eggs', 1, 3.14)
In [ ]:
type(tuple)
In [130]:
tuple_1[0]
Out[130]:
'easter_eggs'
In [132]:
tuple_1[2]
Out[132]:
3.14
In [133]:
tuple_1[2] = 'Cant change the tuple item value as they are immutable'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-133-04f87d6efeaf> in <module>()
----> 1 tuple_1[2] = 'Cant change the tuple item value as they are immutable'

TypeError: 'tuple' object does not support item assignment

List and Tuples

Convert list to tuple

In [144]:
animals_list = ['cat', 'rat', 'cow', 'dog', 'rat']
animals_tuple = tuple(animals_list)
animals_tuple
Out[144]:
('cat', 'rat', 'cow', 'dog', 'rat')
In [142]:
type(animals_list), type(animals_tuple)
Out[142]:
(list, tuple)

Convert tuple to list

In [147]:
animals = ('cat', 'rat', 'cow', 'dog', 'rat')
print (list(animals))
['cat', 'rat', 'cow', 'dog', 'rat']

Tuples are faster than list

In [88]:
import timeit
print ('List execution time :', timeit.timeit('[1,2,3,1,7,1,2,3,1,7]', number=100000))
print ('Tuple execution time:',timeit.timeit('(1,2,3,1,7,1,2,3,1,7)', number=100000))
List execution time : 0.011051107368757584
Tuple execution time: 0.0031230319397081985

for loop with tuple

In [145]:
animals = ('cat', 'rat', 'cow', 'dog', 'rat')

for animal in animals:
    print (animal)
cat
rat
cow
dog
rat

len ()

In [148]:
animals = ('cat', 'rat', 'cow', 'dog', 'rat')
print (len(animals))
5

empty tuple

We can create an empty tuple using () notation or tuple() function.

In [8]:
# empty tuple
animals = ()                                 # or try # tuple()
print ('Data type =', type(animals))
print ('No of elements =', len(animals))
Data type = <class 'tuple'>
No of elements = 0

in & not in operators

In [150]:
animals = ('cat', 'rat', 'cow', 'dog', 'rat')
print ('cat' not in animals)
False

Multiple data assignment using tuple

In [171]:
a = 1
b = 2
a,b = b,a               # swap a,b values using tuple assignemnt
print ('a = ' + str(a))
print ('b = ' + str(b))
a = 2
b = 1
In [165]:
name,height, weight = ('Christian Bale', 1.86, 90)
In [167]:
print (name)
print (height)
print (weight)
Christian Bale
1.86
90

Dictionaries

We have already seen bool, int, float, list, tuple built-in data types. dict (dictionary) is my second favortie data type in Python, next to list.

  • dict provides flexible way to access and organize data.
  • dictionaries are identified with flower brackets { and } with key:value format inside, whereas
    • lists are identified by sqaure brackets [ and ] and
      • tuple is identified by ( and )
In [152]:
animal_sounds = {'cat': 'meow',
                 'dog': 'lol',
                 'cow': 'moo',
                 'ducks': 'quack'
                }
print (animal_sounds)
{'cat': 'meow', 'dog': 'lol', 'cow': 'moo', 'ducks': 'quack'}
In [153]:
animal_sounds['cow']
Out[153]:
'moo'

To ponder : What happens when you try to access an element with key that doesn't exist in tuple? 🤔

list vs dict

  • In list data type, we access its elements using the index number that starts from 0.
  • On the other hand, in dict data type, we access the items/values using keys.
    • Indexes for dictionary are called keys.
    • Key with its associated value is called key-value pair.
  • Unlike list,

    • dictionary keys can be of many different data types.
    • dictionary items are unordered.
    • dictionaries cannot be sliced.
  • Though dictionaries are not ordered, its flexibility allows to orgranize data in powerful ways.

keys(), values(), items()

These 3 dictionary methods will return list like values which can be used in loops.

In [155]:
animal_sounds = {'cat': 'meow',
                 'dog': 'lol',
                 'cow': 'moo',
                 'ducks': 'quack'
                }
print (animal_sounds)
{'cat': 'meow', 'dog': 'lol', 'cow': 'moo', 'ducks': 'quack'}
In [156]:
animal_sounds.keys()          # returns a list of keys
Out[156]:
dict_keys(['cat', 'dog', 'cow', 'ducks'])
In [157]:
animal_sounds.values()        # returns a list of values
Out[157]:
dict_values(['meow', 'lol', 'moo', 'quack'])
In [159]:
animal_sounds.items()         # returns a list of key-value pairs
Out[159]:
dict_items([('cat', 'meow'), ('dog', 'lol'), ('cow', 'moo'), ('ducks', 'quack')])
In [163]:
for key in animal_sounds.keys():
    print (key, ',', animal_sounds[key])
cat , meow
dog , lol
cow , moo
ducks , quack
In [164]:
for key,value in animal_sounds.items():
    print (key, ',', value)
cat , meow
dog , lol
cow , moo
ducks , quack

len()

In [12]:
animal_sounds = {'cat': 'meow',
                 'dog': 'lol',
                 'cow': 'moo',
                 'ducks': 'quack'
                }
print (len(animal_sounds))
4

empty dictionary

We can create empty dictionary using {} notation or dict() function.

In [13]:
animal_sounds = {}                        # or try # dict()
print ('Data type =', type(animal_sounds))
print ('No of elements =', len(animal_sounds))
Data type = <class 'dict'>
No of elements = 0

in & not in operators

In [177]:
data = {'name':'Christian Bale',
        'height': 1.86, 
        'weight': 90}
print (data)
{'name': 'Christian Bale', 'height': 1.86, 'weight': 90}
In [181]:
90 in data.keys(), 90 in data.values()
Out[181]:
(False, True)

get()

  • Used to check whether a key exists in a dictionary before accessing the key's value
  • get() method takes 2 arguments
    • key of the value to retrieve
    • fallback value to return if key doesn't exist
In [183]:
data = {'name':'Christian Bale',
        'height': 1.86, 
        'weight': 90}
print (data)
{'name': 'Christian Bale', 'height': 1.86, 'weight': 90}
In [184]:
data['age']           # without get() method, there's no fallback value
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-184-1743a0764bb4> in <module>()
----> 1 data['age']

KeyError: 'age'
In [187]:
data.get('age', 30)    # As the dictionary doesn't have age key, it returns the fall back value provided
Out[187]:
30
In [186]:
data.get('name', 'Unknown')
Out[186]:
'Christian Bale'

Strings

We have already seen bool, int, float, list, tuple& dict built-in data types. str (string) is my third favortie data type in Python, next to list & dict.

Handling text such as emails, documents, web scraping is one of the most commong forms of data our program needs to handle. With Python, we can do lot of cool stuff with strings.

str data type

  • str data type starts and ends with quotes (could be single or double).
  • str data type is immutable
    • i.e. Values once assinged cannot be changed through indexing.
In [190]:
str1 = 'hi welcome to my home'
str2 = "hola bienvenido a mi casa"
In [191]:
print (str1, type(str1))
print (str2, type(str2))
hi welcome to my home <class 'str'>
hola bienvenido a mi casa <class 'str'>

len ()

In [215]:
str1 = 'hi welcome to my home'
len(str1)
Out[215]:
21

emptry string

We can create empty string using '' notation or str() function.

In [214]:
empty_string = ''          # No characters inside empty string    # or try # str()
print (len(empty_string))
0

str index

  • Indexing a string to get the corresponding character is similar to indexing list or tuple data type.
  • Index no starts from 0
In [195]:
batman = 'Bruce Wayne!'
print (batman)
Bruce Wayne!
String Index Position
Letter B r u c e W a y n e !
Index no 0 1 2 3 4 5 6 7 8 9 10 11
Index no (Reverse) -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1

The space and exclamation point are included in the string character and is counted as one character/ letter

In [198]:
batman[0]
Out[198]:
'B'
In [199]:
batman[-12]
Out[199]:
'B'
In [201]:
batman[5]
Out[201]:
' '

As string data type is immutable, an individual index position cannot be assigned a new value. In order to do that the entire string data type should be overwritten

In [202]:
batman[5] = '-'         
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-202-dbb14015b79f> in <module>()
----> 1 batman[5] = '-'

TypeError: 'str' object does not support item assignment
In [204]:
batman = 'Bruce-Wayne!'            # Overwritting the string data type with new vale
print (batman)
Bruce-Wayne!

str slicing

str slicing is very similar to slicing a list data type

In [205]:
batman = 'Bruce Wayne!'
print (batman[1:5])
ruce

str slicing returns an empty string when there is no element to slice in the given range.

In [211]:
print ('-' + batman[12:15] + '-')       # returns an empty string
--

in & not in operators

  • Works similar to list data type
  • They check whether first string can be found withing second string
In [218]:
batman = 'Bruce Wayne!'
print ('Bruce' in batman)
True
In [220]:
print ('bruce' in batman)    # Python is case-sensitive
False
In [221]:
print ('Wayne' not in batman)    
False

isXXX() methods

There are several string methods that have names beginning with the word is. These methods return a bool value that describes the nature of the string. Here are some common isX string methods:

  • isupper() returns True if the string has at least one letter and all the letters are uppercase.

  • islower() returns True if the string has at least one letter and all the letters are lowercase.

  • isalpha() returns True if the string consists only of letters and is not blank.

  • isalnum() returns True if the string consists only of letters and numbers and is not blank.

  • isdecimal() returns True if the string consists only of numeric characters and is not blank.

  • isspace() returns True if the string consists only of spaces, tabs, and new-lines and is not blank.

  • istitle() returns True if the string consists only of words that begin with an uppercase letter followed by only lowercase letters

WHY WE NEED IT? The isX string methods are helpful when you need to validate user input & to make the code smarter and more generic/ fool proof.

In [225]:
spam = 'Hello world!'
spam.islower()
Out[225]:
False

Set

We have already seen bool, int, float, str, list, tuple& dict built-in data types. Set unlike lists or tuples,

  • cannot have multiple occurrences of the same element => highly useful to efficiently remove duplicate values
  • stores unordered values
  • contains only immutable values (like a str or tuple)

Set are identified with flower brackets { and } similar to dictionary. However, they are different from dictionary as set doesn't have key-value pair.

set data type

In [3]:
dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'}     
print (dataScientist)
{'SAS', 'Python', 'R', 'Tableau', 'Git', 'SQL'}

Take note that unlike list & tuple, the set values are not ordered. The order in which the set values are created and stored/ printed are different.

len()

In [14]:
dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'}     
len(dataScientist)
Out[14]:
6

Empty set

  • Unlike list, dict, tuples, there is no notation for an empty set. We have to explicitly write it as set()
In [20]:
dataScientist_dict = {}                         # Creates an empty dictionary
print ('Data type =', type(dataScientist_dict))
print('No of elements =', len(dataScientist_dict))

dataScientist_set = set()                        # Creates an empty set
print ('Data type =', type(dataScientist_set))
print('No of elements =', len(dataScientist_set))
Data type = <class 'dict'>
No of elements = 0
Data type = <class 'set'>
No of elements = 0

List and Sets

Convert list to sets

In [38]:
dataEngineer = set(['Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'])  
print (dataEngineer)
{'Scala', 'Python', 'Hadoop', 'Java', 'Git', 'SQL'}

Convert sets to list

In [41]:
dataEngineer = {'Scala', 'Python', 'Hadoop', 'Java', 'Git', 'SQL'}

dataEngineer_list = list(dataEngineer)
print (dataEngineer_list)
['Scala', 'Python', 'Hadoop', 'Java', 'Git', 'SQL']

Convert sets to Ordered list

In [47]:
dataEngineer = {'Scala', 'Python', 'Hadoop', 'Java', 'Git', 'SQL'}
print (sorted(dataEngineer))           # Sort in alphabetical order (A-Z)
['Git', 'Hadoop', 'Java', 'Python', 'SQL', 'Scala']
In [49]:
sorted(dataEngineer, reverse=True)   # Sort in reverse alphabetical order (Z-A)
Out[49]:
['Scala', 'SQL', 'Python', 'Java', 'Hadoop', 'Git']

Remove duplicates from list

  • By converting the list to set data type, the duplicates will be automatically removed.
  • Infact, removing duplicates this way is more time efficient than writing our own code to do it.
In [55]:
num = [1,1,1,1,2,2,2,3,4,4,5,5,5]
print ('Before :', num)
print ('After  :', list(set(num)))     # Convert the value to set and back to list again (duplicates are removed)
Before : [1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5]
After  : [1, 2, 3, 4, 5]

Add & remove values from set

Add values to set

In [30]:
dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau'}     
dataEngineer.add('SoS')
print (dataEngineer)
{'Scala', 'Python', 'Hadoop', 'Java', 'SoS', 'Git', 'SQL'}

Remove values from set

There are 2 ways to remove values from set

  1. Using remove() method - The shortfall of using this is if we try to remove a value that is not in your set, we will get a KeyError.
  2. Using discard() method - This will not throw Error if the value is not found. This is equivalent to get() method in dict.
In [33]:
dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau'}     
dataScientist.remove('Python')
print(dataScientist) 
{'R', 'Tableau', 'Git', 'SQL'}
In [35]:
dataScientist.remove('Java')          # Throws error as the value is not inside the set
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-35-ce19914cb54d> in <module>()
----> 1 dataScientist.remove('Java')          # Throws error as the value is not inside the set

KeyError: 'Java'
In [36]:
dataScientist.discard('Java')  

Set operations

A common use of sets in Python is computing standard math operations such as union, intersection, difference, and symmetric difference.

  • set.union(A,B) - All values that are members of A or B or both
  • set.intersection(A,B) - All values that are members of both A and B
  • set.difference(A,B) - All values of A that not in B
  • set.symmetric_difference(A,B) - All values which are in one of the sets, but not in both
    • <=> set.union(A,B) - set.intersection(A,B)
In [3]:
dataScientist = set(['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'])
dataEngineer = set(['Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'])
In [77]:
# For visualization purpose - 2 Circle VENN diagrams
import matplotlib.pyplot as plt
from matplotlib_venn import venn2, venn2_circles

plt.figure(figsize=(7,7))
subset_10 = '\n\n'.join(list(set.difference(dataScientist, dataEngineer)))
subset_01 = '\n\n'.join(list(set.difference(dataEngineer,dataScientist)))
subset_11 = '\n\n'.join(list(set.intersection(dataScientist, dataEngineer)))

v = venn2(subsets={'10': 3, '01': 3, '11': 3}, set_labels = ('dataScientist', 'dataEngineer'))
c = venn2_circles(subsets=(1, 1, 1), linestyle='solid', linewidth=1.0)
v.get_label_by_id('10').set_text(subset_10);v.get_label_by_id('10').set_fontsize(12)
v.get_label_by_id('01').set_text(subset_01);v.get_label_by_id('01').set_fontsize(12)
v.get_label_by_id('11').set_text(subset_11);v.get_label_by_id('11').set_fontsize(12)
plt.show()
In [7]:
set.union(dataScientist, dataEngineer)                 
Out[7]:
{'Git', 'Hadoop', 'Java', 'Python', 'R', 'SAS', 'SQL', 'Scala', 'Tableau'}
In [91]:
set.intersection(dataScientist, dataEngineer)
Out[91]:
{'Git', 'Python', 'SQL'}
In [92]:
set.difference(dataScientist, dataEngineer)
Out[92]:
{'R', 'SAS', 'Tableau'}
In [93]:
set.symmetric_difference(dataScientist, dataEngineer)
Out[93]:
{'Hadoop', 'Java', 'R', 'SAS', 'Scala', 'Tableau'}
In [95]:
set.union(dataScientist, dataEngineer) - set.intersection(dataScientist, dataEngineer)
Out[95]:
{'Hadoop', 'Java', 'R', 'SAS', 'Scala', 'Tableau'}
In [85]:
subset = {'R', 'SAS'}
set.issubset(subset, dataScientist), set.issubset(subset, dataEngineer)
Out[85]:
(True, False)

in and not in operators

  • Works similar to checking in list and tuple
    • in <=> element ∈ set
    • not in <=> element ∉ set
In [79]:
possibleSet = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS', 'Java', 'Spark', 'Scala'}
In [82]:
# Membership test
'Python' in possibleSet, 'C++' not  in possibleSet
Out[82]:
(True, True)

Reading and Writing Files

To download all the files used in the Python Refresher project, visit link here

.txt files

open()

Python has a built-in functions open() with which we can open the file and read its contents. The function returns a file handle if the requested file exisits & we have proper permission to read the file.

  • Opening doesn't mean reading the data. It just establishes the connectedion between RAM & Harddisk.
  • file handle - A variable used to manipulate the file. Equivalent to File > Open in Microsoft Word.

Note: Handle doesn't have all the file data. It simply establishes a connection.

In [164]:
f_name = 'files/read-file-example.txt'   # For mac & linux users, change the directory slashes accordingly
f_handle = open(f_name)
In [165]:
print (f_handle)
<_io.TextIOWrapper name='files/read-file-example.txt' mode='r' encoding='cp1252'>

file handle

In its simplest form, a file handle for reading data works sort of like a pipe: the operating system puts data (usually strings) in one end, and we extract data out of the other end, usually one line at a time.

fhandle_read_file

Read/ print every line in a file

  • Though the file handle doesn't contain the file data, we can use for loop to read the contents of the file line by line.
In [32]:
for line in f_handle:
    print (line)
This is Line 1.

This is Line 2.

This is Line 3.

This is Line 4.

This is Line 5 (last line).

Why open() does't read entire file?

Some files might be quite large with many GBs of data. The open() just created a handle to read the file contents. Then, for loop actually reads the data from the file. This way, Python takes care of splitting the data in the file into separate lines using the newline character \n. Because the for loop reads the data one line at a time, it can efficiently read and count the lines in very large files without running out of main memory (RAM) to store the data.

readline() - To read text file one line at a time

In [166]:
f_name = 'files/read-file-example.txt'
f_handle = open(f_name)
print (f_handle.readline())
print (f_handle.readline())
This is Line 1.

This is Line 2.

readlines() - To read all the lines in the text file

In [167]:
f_name = 'files/read-file-example.txt'
f_handle = open(f_name)
print (f_handle.readlines())
['This is Line 1.\n', 'This is Line 2.\n', 'This is Line 3.\n', 'This is Line 4.\n', 'This is Line 5 (last line).']

read() entire file

If we know the file is relatively small compared to the size of your main memory, we can read the whole file into one string using the read() on the file handle.

In [168]:
f_name = 'files/read-file-example.txt'
f_handle = open(f_name)
file_content = f_handle.read()
print (file_content)
This is Line 1.
This is Line 2.
This is Line 3.
This is Line 4.
This is Line 5 (last line).

write() a line into file

fhandle_write_file

In [18]:
line1 = 'This is Line 1.\n'

To write a file, we have to open it with mode w as second parameter.

In [169]:
f_name = 'files/write-file-example-1.txt'
fhandle = open(f_name, 'w')

The write() method of the file handle object puts data into the file, returning the number of characters written.

In [16]:
fhandle.write(line1)          # Writes the line into the text file and returns the no of characters written
Out[16]:
16

close() the file

When we are done writing, we have to explicitly close the file to make sure that the last bit of data is physically written to the hard disk disk from the buffer so it will not be lost if the power goes off.

In [17]:
fhandle.close()

fhandle_close_file

write multiple lines into a file using for loop and write()

In [29]:
line1 = 'This is Line 1.\n'
line2 = 'This is Line 2.\n'
line3 = 'This is Line 3 (last line).\n'
lines = [line1, line2, line3]
print (lines)
['This is Line 1.\n', 'This is Line 2.\n', 'This is Line 3 (last line).\n']
In [170]:
f_name = 'files/write-file-example-2.txt'
fhandle = open(f_name, 'w')
for line in lines:
    fhandle.write(line)
fhandle.close()

writelines()

write multile lines into a file

In [32]:
f_name = 'files\\write-file-example-2.txt'
fhandle = open(f_name, 'w')
fhandle.writelines(lines)
fhandle.close()

open() Mode

Including a mode argument is optional because a default value of 'r' will be assumed if it is omitted. The 'r' value stands for read mode, which is just one of many.

The modes are:

    ========= ===============================================================
    Character| Meaning
    --------- ---------------------------------------------------------------
    'r'      | open for reading (default)
    'w'      | open for writing, truncating the file first
    'x'      | create a new file and open it for writing
    'a'      | open for writing, appending to the end of the file if it exists
    'b'      | binary mode
    't'      | text mode (default)
    '+'      | open a disk file for updating (reading and writing)
    'U'      | universal newline mode (deprecated)
    ========= ===============================================================

To append a file

  • For example, the append 'a' mode doesn't overwrite the existing contents of the file.
In [175]:
f_name = 'files/write-file-example-2.txt'
fhandle = open(f_name, 'a')
fhandle.writelines(lines)
fhandle.close()

.csv files

What is .csv file?

  • a very popular import and export data format used in spreadsheets and databases.
  • comma-separated values (CSV) file is a delimited text file that uses a comma to separate values.
  • A CSV file stores tabular data (numbers and text) in plain text.
  • Each line of the file is a data record.
    • Each record consists of one or more fields, separated by commas.

Python csv module

  • Contains classes related to reading and writing tabular data in CSV format
In [93]:
header = ['Hero Name', 'symbol', 'height', 'weight']
data = [['Batman', 'bat', 1.82, 85],
        ['Ironman', 'S', 1.78, 300],
        ['Spiderman', 'Spider', 1.62, 70]]

csv.writer()

In [172]:
import csv

f_name = 'files/write-csv-example-1.csv'     # For mac & linux users, change the directory slashes accordingly
f_handle = open(f_name, 'w',  newline='')

csv_writer = csv.writer(f_handle)

csv_writer.writerow(header)
for line in data:
    csv_writer.writerow(line)
    
f_handle.close()

csv.reader()

In [173]:
import csv
f_name = 'files/write-csv-example-1.csv'    # For mac & linux users, change the directory slashes accordingly
f_handle = open(f_name, 'r')
csv_reader = csv.reader(f_handle)
for line in csv_reader:
    print (line)
    
f_handle.close()
['Hero Name', 'symbol', 'height', 'weight']
['Batman', 'bat', '1.82', '85']
['Ironman', 'S', '1.78', '300']
['Spiderman', 'Spider', '1.62', '70']

Others

zip()

  • Make an iterator that aggregates elements from each of the iterables.
  • Returns an iterator of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The iterator stops when the shortest input iterable is exhausted.
In [101]:
x = [1,2,3]
y = [4,5,6]
z = [7,8,9]
zipped = zip(x,y,z)
print (zipped, type(zipped))

for i in zipped:
    print (i)
<zip object at 0x0000021D476AEB88> <class 'zip'>
(1, 4, 7)
(2, 5, 8)
(3, 6, 9)

unzip a list

zip() in conjunction with the * operator can be used to unzip a list as shown below

In [107]:
zipped = zip(x,y,z)
l1, l2, l3 = zip(*zipped)
print (l1, l2, l3)
(1, 2, 3) (4, 5, 6) (7, 8, 9)

If the length of the iterables are not equal, zip creates the list of tuples of length equal to the smallest iterable and truncates the extra elements.

In [98]:
names = ['Clark Kent', 'Bruce Wayne', 'Peter Parker', 'Tony Stark']
speical_names = ['Super Man', 'Bat Man', 'Spider Man']
color = ['Blue', 'Black']                                         
zipped = zip(names,speical_names,color)

for i in zipped:
    print (i)     # As color is the shortest iterable, zip stops with 2 iterations
('Clark Kent', 'Super Man', 'Blue')
('Bruce Wayne', 'Bat Man', 'Black')

Sample Projects

email parsing & scraping

We will work on mbox.txt file which holds collections of publically availale email messages that are are concatenated and stored as plain text in a single file. For further details on mbox, refer https://en.wikipedia.org/wiki/Mbox.

We are going to parse and scrape through the txt file to extract information about senders, their email address, no of emails sent by each sender and the time at which emails are sent.

To do this, we will need a basic knowledge of for loop, string slicing, splitting & searching, list, dict.

In [142]:
f_name = 'files/mbox.txt'   # For mac & linux users, change the directory slashes accordingly
f_handle = open(f_name)

email_list = []
for row in f_handle:
    # Extract the row that startswith the word 'From ' and store in a list
    if row.startswith('From '):
        email = row.strip()
        email_list.append(email)

Find the no of times email received from each sender

In [147]:
email_dict = {}
for row in email_list:
    email = row.split(' ')[1]
    email_dict[email] = email_dict.get(email, 0) + 1

email_dict
Out[147]:
{'a.fish@lancaster.ac.uk': 14,
 'aaronz@vt.edu': 110,
 'ajpoland@iupui.edu': 48,
 'antranig@caret.cam.ac.uk': 18,
 'arwhyte@umich.edu': 27,
 'bahollad@indiana.edu': 4,
 'bkirschn@umich.edu': 27,
 'chmaurer@iupui.edu': 111,
 'colin.clark@utoronto.ca': 1,
 'csev@umich.edu': 19,
 'cwen@iupui.edu': 158,
 'david.horwitz@uct.ac.za': 67,
 'dlhaines@umich.edu': 84,
 'gbhatnag@umich.edu': 3,
 'ggolden@umich.edu': 8,
 'gjthomas@iupui.edu': 44,
 'gopal.ramasammycook@gmail.com': 25,
 'gsilver@umich.edu': 28,
 'hu2@iupui.edu': 7,
 'ian@caret.cam.ac.uk': 96,
 'jimeng@umich.edu': 93,
 'jleasia@umich.edu': 2,
 'jlrenfro@ucdavis.edu': 1,
 'john.ellis@rsmart.com': 8,
 'josrodri@iupui.edu': 28,
 'jzaremba@unicon.net': 9,
 'kimsooil@bu.edu': 14,
 'knoop@umich.edu': 5,
 'ktsao@stanford.edu': 12,
 'lance@indiana.edu': 8,
 'louis@media.berkeley.edu': 24,
 'mbreuker@loi.nl': 9,
 'mmmay@indiana.edu': 161,
 'nuno@ufp.pt': 28,
 'ostermmg@whitman.edu': 17,
 'ray@media.berkeley.edu': 32,
 'rjlowe@iupui.edu': 90,
 'sgithens@caret.cam.ac.uk': 43,
 'ssmail@indiana.edu': 5,
 'stephen.marquard@uct.ac.za': 29,
 'stuart.freeman@et.gatech.edu': 17,
 'thoppaymallika@fhda.edu': 1,
 'tnguyen@iupui.edu': 6,
 'wagnermr@iupui.edu': 44,
 'zach.thomas@txstate.edu': 17,
 'zqian@umich.edu': 195}
In [152]:
email_dict.values()
Out[152]:
dict_values([29, 24, 195, 90, 158, 28, 44, 18, 25, 67, 32, 161, 17, 6, 111, 110, 96, 19, 93, 28, 5, 27, 84, 7, 43, 27, 3, 44, 14, 48, 8, 5, 1, 28, 17, 12, 17, 8, 2, 8, 1, 14, 4, 9, 9, 1])

Finding the email id who sent max no of emails

In [162]:
max_email = max(email_dict.values())
for email, count in email_dict.items():
    if count == max_email:
        print (email, count)
        break
---Finding the email id who sent max no of emails:---
zqian@umich.edu 195

Find total number of emails received in a hourly basis

In [145]:
email_hrs = {}
for row in email_list:
    hr = int(row.split()[5].split(':')[0])
    email_hrs[hr] = email_hrs.get(hr, 0) + 1
In [146]:
email_hrs
Out[146]:
{0: 23,
 1: 10,
 2: 11,
 3: 19,
 4: 23,
 5: 10,
 6: 45,
 7: 42,
 8: 72,
 9: 166,
 10: 198,
 11: 154,
 12: 108,
 13: 114,
 14: 150,
 15: 152,
 16: 181,
 17: 97,
 18: 58,
 19: 46,
 20: 36,
 21: 36,
 22: 28,
 23: 18}
In [141]:
import matplotlib.pyplot as plt
x = list(email_hrs.keys())
height = list(email_hrs.values())
plt.bar(x, height )
plt.title('Emails received in each hour')
plt.xlabel('Hour of the day'); plt.ylabel('No of emails recevied')
plt.show()

tic-tac-toe

In [188]:
# -*- coding: utf-8 -*-
"""
Created on Thu Jun 14 21:20:40 2018

@author: Prasanth
"""

# Create an empty tic tac toe board
theBoard = {1: ' ', 2: ' ', 3: ' ',
            4: ' ', 5: ' ', 6: ' ',
            7: ' ', 8: ' ', 9: ' '}

# List of winning combinations
winningCombos = [[1,2,3],
                 [4,5,6],
                 [7,8,9],
                 [1,4,7],
                 [2,5,8],
                 [3,6,9],
                 [1,5,9],
                 [3,5,7]]

def printBoard(board):
    print (board[1] + '|' + board[2] + '|' + board[3] + '\n' + 
           '-+-+-\n' + 
           board[4] + '|' + board[5] + '|' + board[6] + '\n' + 
           '-+-+-\n' + 
           board[7] + '|' + board[8] + '|' + board[9])
    
def resetBoard():
    theBoard = {1: ' ', 2: ' ', 3: ' ',
                4: ' ', 5: ' ', 6: ' ',
                7: ' ', 8: ' ', 9: ' '}
    return theBoard
    
printBoard(theBoard)
    
player = 'X' 
winFlag = 0
counter = 0

while True:
    try:
        user_input = input('Turn for ' + player + ". Move on which space? ")
        user_input = int(user_input)
        if  theBoard.get(user_input,'') != ' ':
            print ('Invalid input : Try again')
            continue
    except ValueError:
        print ('Invalid input : Try again')
        continue
    except:
        quit()
        break

    theBoard[user_input] = player
    
    printBoard(theBoard)
    
    # If the player wins, inform
    for combo in winningCombos:
        if theBoard[combo[0]] == theBoard[combo[1]] == theBoard[combo[2]] == player:
            print ("player " + player + " wins")
            winFlag = 1 
            break
    
    counter += 1
    
    if winFlag == 1 or counter == 9:
        user_input = input('Game over. Do you want to continue (y or n): ')
        if user_input == 'n' :
            break
        else:
            winFlag = 0
            counter = 0
            theBoard = resetBoard()
            print ('\n'*3)
            printBoard(theBoard)
            
    # toggle player
    if player == 'X':
        player = 'O'
    else:
        player = 'X'  
 | | 
-+-+-
 | | 
-+-+-
 | | 
Turn for X. Move on which space? 1
X| | 
-+-+-
 | | 
-+-+-
 | | 
Turn for O. Move on which space? 2
X|O| 
-+-+-
 | | 
-+-+-
 | | 
Turn for X. Move on which space? 3
X|O|X
-+-+-
 | | 
-+-+-
 | | 
Turn for O. Move on which space? 4
X|O|X
-+-+-
O| | 
-+-+-
 | | 
Turn for X. Move on which space? 5
X|O|X
-+-+-
O|X| 
-+-+-
 | | 
Turn for O. Move on which space? 6
X|O|X
-+-+-
O|X|O
-+-+-
 | | 
Turn for X. Move on which space? 7
X|O|X
-+-+-
O|X|O
-+-+-
X| | 
player X wins
Game over. Do you want to continue (y or n): y




 | | 
-+-+-
 | | 
-+-+-
 | | 
Turn for O. Move on which space? 2
 |O| 
-+-+-
 | | 
-+-+-
 | | 
Turn for X. Move on which space? 3
 |O|X
-+-+-
 | | 
-+-+-
 | | 
Turn for O. Move on which space? 3
Invalid input : Try again
Turn for O. Move on which space? 2
Invalid input : Try again
Turn for O. Move on which space? 4
 |O|X
-+-+-
O| | 
-+-+-
 | | 
Turn for X. Move on which space? 1
X|O|X
-+-+-
O| | 
-+-+-
 | | 
Turn for O. Move on which space? 5
X|O|X
-+-+-
O|O| 
-+-+-
 | | 
Turn for X. Move on which space? 6
X|O|X
-+-+-
O|O|X
-+-+-
 | | 
Turn for O. Move on which space? 9
X|O|X
-+-+-
O|O|X
-+-+-
 | |O
Turn for X. Move on which space? x
Invalid input : Try again
Turn for X. Move on which space? 8
X|O|X
-+-+-
O|O|X
-+-+-
 |X|O
Turn for O. Move on which space? 7
X|O|X
-+-+-
O|O|X
-+-+-
O|X|O
Game over. Do you want to continue (y or n): n

Encryption & Decryption

Will be added soon

Packages used in this series

In [1]:
import sys
print ("Python version: {}".format(sys.version))
Python version: 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609]
In [3]:
import numpy as np
print ("Numpy version: {}".format(np.__version__))
Numpy version: 1.14.0
In [5]:
import matplotlib
print ("Matplotlib version: {}".format(matplotlib.__version__))
Matplotlib version: 2.1.2
In [7]:
import sklearn
print ("Scikit-learn version: {}".format(sklearn.__version__))
Scikit-learn version: 0.19.1
In [8]:
import scipy
print ("Scipy version: {}".format(scipy.__version__))
Scipy version: 1.0.0
In [2]:
import pandas as pd
print ("Pandas version: {}".format(pd.__version__))
Pandas version: 0.22.0
In [9]:
import mglearn
print ("Mglearn version: {}".format(mglearn.__version__))
Mglearn version: 0.1.6
In [13]:
import graphviz
print ("Graph viz verison: {}".format(graphviz.__version__))
Graph viz verison: 0.8.3
In [10]:
import tensorflow as tf
print ("Tensorflow version: {}".format(tf.__version__))
Tensorflow version: 1.5.0

Acknowledgements