Code from purcellconsult.

1. Numbers in Python

0.4s
Python
###########################################
# Code from python
# Features python variables, numbers, and
# builtin data types
#
#
# By Doug Purcell
# http://www.purcellconsult.com
#
############################################


###############################
# creating variables in python
###############################

a = 5
b = 10
c = a
d = a**2
e = d + 10

#############################################
# to view the output use the print() function
#############################################

print(a)
print(b)
print(c)
print(d)
print(e)
# prints text
print('Hello World')
# prints numbers and text, is really a tuple.
print(5, 'birds')
# prints empty space
print()
###############################
# using python as a calculator
# learn the operators:
# + & -
# * & /
# % & //
# ** and ()
###############################

print(10 + 10)
print(20 - 5)
print(9 * 9)
print(5 / 2)
# floor functionality
print(5 // 2)
print(10 % 3)
print(5 ** 3)
# the parentheses changes order of execution
print(10 - 3 / (5 % 3))
print()
#######################################
# two main types of numbers in python:
# int and float.
########################################

a1 = 5
print(type(a))
# euler's number
b1 = 2.7182818284590452353602874713527
print(type(b1))

# 7.718281828459045
c1 = a1 + b1
print(c1)
# 7.Truncates the mantissa
print(int(c1))
print(float(c1))
print()
##################################################
# reading in text and numbers in python!
# the input() function allows
# you to create interactive and fun programs :-)!
##################################################

# reading in text
your_message = "Hello, Hooman!"
# your_message = input('What\'s your message? ')
print('The message is: ', your_message)


################################################
# reading in numbers. Pass the input() function
# to the int() function.
################################################

# Not working in nextjorunal
# your_int = int(input('Enter any number '))
your_int = 42
print('Your number is: ', your_int)
print()
###########################################
# importing modules
# Gain more functionality by importing
# modules like math
###########################################

import math
from math import degrees
print(math.sin(90))
print(math.cos(180))
print(math.tan(45))
# converts to degrees
print(degrees(math.pi/2))

print(math.pi)
print(math.factorial(4))
print(math.gcd(75, 1000))
print(math.isclose(10, 10.00000000000000000000000000000001))
print(math.exp(3))
print(math.log(16, 2))
print(math.floor(5.5242))
print(math.sqrt(9))
#################################
# Microprogramming session
#
# calculate change for groceries
# area of a triangle
# quadratic equation
#
################################

milk = 2.90
loaf_of_bread = 1.89
pack_of_ham = 4.99
grocery_cost = milk + loaf_of_bread + pack_of_ham

# change = int(input('Enter the amount of change you have in $10, $20, or '                   '$50 portions. '))
change = 20

your_change = change - grocery_cost
print(round(your_change, 2))

# area of a triangle is 1/2 * b * h
# base = float(input('Enter base of a triangle '))
# height = float(input('Enter height of triangle '))
base = 1
height = 2
area = 1/2 * base * height
print('Area of a triangle with base', base, 'and height ', height, 'is', area)
# quadratic formula
# Has two roots:
# x = -b + sqrt(b^2 - 4ac) / 2a
# x = -b - sqrt(b^2 - 4ac) / 2a
# write a program that accepts a, b, and c, then
# returns correct answer

from math import sqrt
# a = float(input('Enter a: '))
# b = float(input('Enter b: '))
# c = float(input('Enter c: '))

a, b, c = 1.0, 1.0, -6.0

x1 = 0
x1 = -b + sqrt(b**2 - (4 * a * c))
x1 = x1 / (2 * a)

x2 = -b - sqrt(b**2 - (4 * a * c))
x2 = x2 / (2 * a)
print('x1 =', x1)
print('x2 =', x2)

2. Control and Repeat

Learn how to control the flow of execution of statements in a program by using if, else, and elif statements.

Learn how to repeat code blocks by using# iteration tools in python such as for and while loops.

# BOOLEAN ALGEBRA: True or False
# ----------------------------------------
# Must understand truth tables
# Used to determine control flow: if/elif/else statements
# Describe boolean type by asking true or false questions
is_the_sky_blue = True
do_cats_bark = False

print(is_the_sky_blue)
print(do_cats_bark)
# The 'and' truth table
# 'and' evaluates to false unless both operands are False

print(True and True)
print(True and False)
print(False and False)
print(False and True)
# or evaluates to true with at least one true operand
print(True or True)
print(True or False)
print(False or False)
print(False or True)
# xor evaluates to true iff one of them is true
print(True ^ True)
print(True ^ False)
print(False ^ True)
print(False ^ False)
# compound statements or combining them
print(True or False or False)
print(True and False or True)
print(True or False and True)
print(not False & (True and True) or False)
# CONTROL FLOW IN PYTHON
# -----------------------
# if/else statement

x, y, z = 5, 10, 15
if x < y and z > y:
    print(x)
else:
    print(y)
# The above could also be rewritten as follows
x, y, z = 5, 10, 15
if x < z > y:
    print(x)
else:
    print(y)
# nested if statement
# is the below logically equivalent to the above?
if x < y:
    if z > y:
        print(x)
else:
    print(y)
# what's the output and why does it happen?
if x < y:
    if z < y:
        print(x)
else:
    print(y)
if x < y:
    if z > y:
        print(x)
    print(y, '\n')
if not x > y:
    print('inverse!', '\n')
# elif statements
# can change multiple conditionals together
var = 10
if var == 1:
    print(var + 10)
elif var == 3:
    print(var + 20)
elif var == 5:
    print(var + 30)
elif var == 7:
    print(var + 50)
elif var == 9:
    print(var + 70)
elif var == 10:
    print(var + 100)
else:
    print('I think it\'s not in here')
# ternary statement allows for assignment of variable based on expression evaluation
test_variable = 1
result = 10 if test_variable else ''
print(result, '\n')
# There's many comparison operators such as <=, >=, !=, etc.
# micro programming sessions
# write a program that reads in input, in miles and converts it
# to feet and kilometers. Here are the conversion units:

# miles = float(input('Enter the miles '))
miles = 50
feet = miles * 5280
inches = miles * 63360
kilometers = miles * 1.60934
meters = miles * 1609.34
print(miles, 'miles', '=', feet, 'ft', inches, 'in', kilometers, 'km', meters, 'm')
# write a program that takes input which represents the miles ran
# and then states if the user ran more than a marathon
# marathon equals 26.22 miles

# miles_ran = float(input('Enter the miles ran '))
miles_ran = 50
if miles_ran >= 26.22:
    print('Ran a marathon')
elif miles_ran < 0:
    print('Can\'t run negative miles!')
else:
    miles_to_go = 26.22 - miles
    print(miles_to_go, 'miles to go')

Iteration in python: Computers are perfect for this, humans not so much! Two main ways to do this is while and for loops.

while loop: while something is true do this

i = 0
while i < 10:
    i += 1
    print(i)
print()
# decrementing with a while loop
j = 50
while j > 0:
    print(j, end=' ')
    j -= 1
print('\n\n')
# fibonacci sequence
# prints the first 10
i, j, count = 0, 1, 0
while count < 10:
    print(i)
    i, j = j, j + i
    count += 1
# simple sequence

# scale = int(input('Enter number to scale the loop by: '))
scale = 10
i, j = 0, 1
while i < 10:
    j *= scale
    print('j =', j, end=' ')
    i += 1
while True:
    pass
Python

Infinite loops have their place e.g. can be used to prompt user input in simple games.

If you want to exit out of a program you could use the break statement.

i = 1
while i < 100000000000000000:
    print(i, end=' ')
    i += 1
    if i % 7 == 0:
        print(i)
        break

The continue statement passes over the conditional statement.

i = 0
while i <= 20:
    i += 1
    if i % 3 == 0:
        continue
    else:
        print(i, end=' ')

nesting loops = a loop inside a loop

i, j = 0, 1
while i < 5:
    while j < 5:
        print('i =', i, 'j =', j, end=' ')
        j += 1
    i += 1
    j = 1  # resets the inner loop
print()

for loop: a popular choice for iterating over data structures.

# range() function generates a sequence of numbers
for x in range(10):
    print(x, end=' ')
print()
# nesting for loops to print multiplication tables of 1 - 12

for x in range(1, 13):
    for y in range(1, 13):
        print(x, 'x', y, '=', x * y)
    print('--------------')
# a fun way to learn nested loops
# is to create patterns with them

# 4 x 4 star square
for x in range(4):
    for y in range(4):
        print('*', end=' ')
    print()
print()

# right triangle
for x in range(6):
    for y in range(x):
        print('*', end=' ')
    print()
print()

# money rectangle
for x in range(3):
    for y in range(10):
        print('$', end=' ')
    print()

Generating prime numbers within the the range 1-1000 known as the sieve's algorithm.

The algorithmic complexity is O(N^2).

for x in range(3, 1000):
    for y in range(2, x):
        if x % y == 0:
            break
    if x == y + 1:
        print(x, end=' ')
print()
# calculating factorials of a number n
# n = int(input('Enter a number n '))
n = 10
count = n-1
while count >= 1:
    n *= count
    count -= 1
print('n =', n)
# read in a list of numbers and print the mean
summation, n = 0, 0
try:
    while True:
        list_of_numbers = float(input('Enter numbers. Terminate by hitting Ctrl + C (keyboard interrupt): '))
        summation += list_of_numbers
        n += 1
except KeyboardInterrupt:
    print()
    print('Program existing...')
    print('-------------------')
    print('summation = ', summation)
    print('count =', n)
    print('average = ', summation / n)

3. String Processing

#########################################
# String processing in python.
# Learn how to create, manipulate,
# format, and harness strings in python.
#
#
#
# By Doug Purcell
# http://www.purcellconsult.com
#
#
##########################################

# creating strings in python

e = 'Hello'
f = 'Bonjour'
s = 'Jambo'
h = 'Namaste'
a = 'Selami'
i = 'Ciao'

# view output with print() statement

print(e)
print(f)
print(s)
print(h)
print(a)
print(i)

Strings can be indexed and manipulated, a.k.a. subscript notation. Indexes start at 0.

print(e[0]) # H
print(f[1]) # o
print(s[2]) # m
print(h[6]) # e

Get ranges in strings by slicing them. string_name[start:end:step]. Start is inclusive, the end is exclusive.

print(a[0:2])   # Se
print(i[0:3])   # Cia
print(s[::2])   # Jmo
# strings can have negative indexes

print(f[-7:-4])     # Bon
print(a[-6:-3])     # Sel
print(i[-1::-1])    # reverses a string
# ways to manipulate strings in python

a = 'Hello'
b = 'friend'
c = a + b
print(c)            # Hellofriend
print(a + ' ' + b)  # Hello friend
d = '9'
print(10 * int(d))

print(a * 5)
# common methods for the string class

text = 'This is a small world'
print(text.count('i'))
print(text.lower())
print(text.upper())
print(' '.join(text))
print(text.split(' '))
print(text.islower())
print(text.isupper())
print(text.isalnum())
print(len(text))
# converts character to computer's number
print(ord('A'))

# converts decimal back to character
print(chr(65))
# iterating with a for loop
text = 'what a wonderful world'
for letter in text:
    print(letter)
# iterating with a while loop
i = 0
while i < len(text):
    print(text[i])
    i += 1
# differences between single, double, and triple quotes.

# single quote
print('What\'s up?')    # the backslash is needed to escape the apostrophe.
print("What's up?")     # the apostrophe is not needed in this case.
print("\"What's up?\"") # the apostrophe is needed to add on the quotes to the text
print("""What's up? Does the "" need an escape?""") # triple quotes can escape single, double, and a lot more.
def triple_quote_docs():
    """
    You know, triple quotes
    can also be used for what's
    knows as a docstring. This let's
    you describe some functionality of the
    method/function, class, etc.
    """
    return

print(triple_quote_docs.__doc__)    # prints the content in triple quotes

Learn about the string module in the python docs.

The various ways to format strings in python:

  • commas
  • %
  • format()
  • f-strings: f"..."
  • template strings
# formatting strings using commas
print('Mixing numbers like ', 8, 'with text')
# the following is allowed
print('9' + '0')
# the following is not allowed
# print('9' + 0)
# the following is allowed
print(float('9') + float('0'))
# using the % sign (the old way)
# similar to the printf() in C
print('Hello World For the %dth time' % 100)
print('%s %s %d %d %f %f' % ('Mercedes', 'Apple', 100, 20, 3.2, 1))
print('This is a +%d integer' % 10)
print('This is a negative -%d integer' % 250)
print('This is a confused -%d integer' % 300)

The format string syntax (Python 3 +)

var_1 = 'test'
var_2, var_3 = 'move it move it', 'MOVE IT!'
dog = 'Lassie'
print('This is a {}'.format(var_1))
print('I like to {}, you like to {}!'.format(var_2, var_3))
print('This is {}, and this is B'.format('A', 'B'))
print('Number {1} and number {0}'.format(100, 200))  # keyword position

# accessing arguments by name
print('Mount Whitney is located at {latitude}°N, and {longitude}°W'.format(latitude='35.5785', longitude='118.2923'))

temp = {'day_one': 90, 'day_two': 100}
print('It is {day_one}° F today and tomorrow it will be {day_two}° F'.format(**temp))
# accessing arguments' items:
point = (5, 10)
print('The point values are {0[0]} and {0[1]}'.format(point))
# accessing an argument's attributes
class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def __str__(self):
        return 'Rectangle({self.length}, {self.width})'.format(self=self)

rect = Rectangle(10, 5.5)
print(rect.__str__())
# aligning text

print('{:<10}'.format('X')) # left align
print('{:>10}'.format('X')) # right align
print('{:^10}'.format('X')) # center
print('{:?^10}'.format('X')) # add a fill character

# formatting binary, octal, and hexadecimals
print('Binary number: {0:b}'.format(50))
print('Octal number: {0:o}'.format(100))
print('Hexadecimal number: {0:x}'.format(2555))

# using commas as a delimiter
print('{:,}'.format(2783727282727)) # 2,783,727,282,727
print('{:.2%}'.format(90.60/100))   # 90.60%

f strings (Python 3.6+):

item_1, item_2, item_3 = 'computer', 'mouse', 'browser'
print(f"He uses a {item_1}.")
print(f"He uses a {item_2} and a {item_3}.")
print(f"He uses a {item_1} 3 times a day.")
from string import Template
poem = Template('$x are red and $y are blue')
print(poem.substitute(x='roses', y='violets'))

4. A Gentle Intro to Data Structures

What's a data structure? A way for computers to store and retrieve data. A data structure may be selected or designed to store data for the purpose of working on it with various algorithms. Data structures are popular interview questions during technical exams at software companies. It's important to pick the proper data structure for the particular problem you're working on. An ill suited data structure could lead to poor performing programs. Python has 4 builtin data structures, and many more that can be imported to use in your various programs.

4.1. lists

A data structure that stores data in a linear fashion. The elements, or 'data' inside of a list is typically homogeneous, similar to an array in other languages. However heterogenous lists (lists with elements of different types) are also allowed in Python.

empty = []

# use the append method to add data into a list
# you can only add one element at a time.
empty.append(10)
empty.append(100)
empty.append(50)
print(empty)

Accessing elements in lists with the index, starting from 0.

evens = [2, 4, 6, 8, 10, 12, 14]
print(evens[0])      # 2
print(evens[2])      # 6
print(len(evens)-1)  # 6
# in python you can also use negative indices
print(evens[-1])    # 14
print(evens[-3])    # 10
# you can slice lists or take a range of numbers
print(evens[0:3])   # 2, 4, 6
print(evens[::])    # returns everything
print(evens[::2])   # returns everything with a skip of 2
print(evens[-7:-3]) # 2, 4, 6, 8
print(evens[::-1])  # reverses the list
# common functions and methods associated with lists
# len() gets the size
size = len(evens) # 7
evens.extend([13, 17, 19, 23])    # adds another list the the current one
print(evens)
evens.reverse()                   # reverses the list
print(evens)
print(evens.count(13))             # 1
print(evens.pop())                 # 2
evens.insert(0, 29)
print(evens)
# iterating or walking through lists
# you can use a for or while loop to iterate over a list
primes = [2, 3, 5, 7, 11, 13, 17, 19]
for x in primes:
    print(x, end=' ')

print()
# if you use a while loop you must access the elements
# using subscript notation
i = 0
while i < len(primes):
    print(primes[i], end=' ')
    i += 1
# nested lists
# a list within a list is a 2D or two dimensional list

grid_1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]


# better formatted
print(grid_1)

grid_2 = [
 [1, 2, 3],
 [4, 5, 6],
 [7, 8, 9]
]

print(grid_2[0][0])     # 1
print(grid_2[0][1])     # 2
print(grid_2[1][1])     # 5
print(grid_2[2][0] * grid_2[2][2])  # 63
# to iterate through all of the rows and columns of a 2D list you'll need a nested loop
for row in range(len(grid_2)):
    for col in range(len(grid_2)):
        print(grid_2[row][col], end=' ')
    print()
# list comprehensions: a shorthand version for creating lists

a = []
for x in range(10):
    a.append(x)
print(a)

# instead do the following
b = [x for x in range(10)]
print(b)

# build list of even integers from 0 .. 100
c = [x for x in range(100) if x % 2 == 0]
print(c)

# nested list comprehensions
d = [x for x in range(1, 3) for y in range(1, 7)]
print(d)

4.2. tuples

tuples are very similar to lists with the exception that tuples are immutable. Meaning that the object is immutable.

point = (1, 5)
print(point)            # 2
print(point.count(1))   # 1
print(point.index(5))   # 1
print(len(point))       # 2
print(point[::])        # (1, 5)
print(point[1])         # 5

# iterating over tuples
for x in point:
    print(x, end=' ')
print()

4.3. dictionaries

Also known as hash tables, hash maps, or associative arrays in other languages, containing key/value mappings, a very ubiquitous data structure.

Used for database / dataframe indexing.

Use curly braces to build them.

vowels_1 = {'a': 0, 'e': 1, 'i': 2, 'o': 3, 'u': 4}

# could also change format

vowels_2 = {
    'a': 0,
    'e': 1,
    'i': 2,
    'o': 3,
    'u': 4
}

# accessing elements in dictionaries
# can use subscript notation to get the value

print(vowels_1['a'])
print(vowels_1.items()) # returns all key/value mappings
print(vowels_1.pop('o'))
print(vowels_1.keys())      # returns all of the keys
print(vowels_1.values())    # gets all of the values
print(vowels_1.get('a'))

4.4. sets

Similar to sets in mathematics, they can't hold duplicates.

They also use curly braces, and the order is not preserved.

letters = {'a', 'A', 'a', 'b', 'b', 'c', 'd', 'e', 'e', 'f'}
print(letters)
# common set functions
# set operations like in mathematics

constants = {'a', 'b', 'c'}
print(letters.union(constants))                 # returns first set combined with elements of second
print(letters.difference(constants))            # returns a set that subtracts the second from the first
print(letters.intersection(constants))          # returns elements common
print(letters.symmetric_difference(constants))  # (A-B) U (B-A)

# like with the other data structures, they can also be
# iterated over.

for x in letters:
    print(x, end=' ')

5. Functions and Functional Programming

What's a function in mathematics? A relation between the mapping of a set of inputs to a set of outputs e.g. x^2, x^3, or sqrt(x + 3).

Why use functions?

  1. Makes code more modular
  2. Allows code reuse
  3. Abstraction. You don't need to know the complex underlining details everytime.

How to create functions in python:

def f():
    pass
Python
  • def is a reserved keyword in python
  • f is the name of the function
  • The open ( and close ) parentheses must follow the function name (no spaces allowed)
  • The colon must follow the closing parentheses (no spaces allowed)
  • 'underneath' the function name is called the body. The details of the function goes here.
  • The body of a function must be indented four spaces.
  • A function could optionally return a value.

What's the difference between parameters and arguments?

  • A parameter is a variable which goes inside the parentheses of a function
  • An argument is an expression within parentheses.

5.1. A function declaration in python

def sum_nums(x, y):
    return x + y
  
# to call or use the function do the following
result = sum_nums(5, 10)    # 15
# the return statement allows you to store the result for later reuse
def summation(x, y, z):
    """Sums three numbers"""
    return x + y + z


a = summation(5, 10, 15)
b = summation(10, 20, 30)
c = a + b
print(c)

5.2. Collecting (positional) argumants

The star operator (*) packs and unpacks tuples. It could collect (positional) arguments of arbitrary numbers.

def summation(*args):
    """sums an arbitrary amount of numbers"""
    sum = 0
    for x in args:
        sum += x
    return sum

x = summation(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
print(x)

5.3. Keyword arguments

Use these when you want your arguments to have default values.

def f(x=10, y=20):
    return (x + y) * 3

print(f(x=20, y=100)) # 360

Passing in an arbitrary number of keyword arguments: double star operator (**).

def func(**kwargs):
    for x, y in kwargs.items():
        print('x={}, y={}'.format(x, y))

func(a=1, b=5, c=10)

5.4. lambda , anonymous (nameless) function

# We bind the name of x1 to an anonymous function
x1 = lambda x, y: x + y
print(x1(20, 20))   # 30
# filter: allows you to filter the result
items = [x for x in range(1, 1001)]
x2 = filter(lambda x: x % 3 == 0, items)
print(list(x2))
# map: returns a list of results after applying the function to each item in the list
nums = [x for x in range(1, 11)]
mapped = map(lambda x : x** 2, nums)
print(list(mapped))
# reduce: apply a function passed in the argument to all of the elements in a list.
first_1000 = [x for x in range(1001)]
import functools
print('The summation is:',  functools.reduce(lambda x, y: x + y, first_1000))

6. Unit Test Module

Testing your programs aginst breakage is neccesary in software engineering, a.k.a. test-driven development.

  • A unit testing framework inspired by JUnit
  • Built into the python coreSupports test automation, sharing of setup and shutdown of code tests
  • Aggregation of tests into collections and independence of tests from reporting framework

The unittest module can be used from the command line. To run tests from modules, classes, or individual methods:

python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
Bash

Common assert methods in unittest:

  • assertEqual(a, b)
  • assertNotEqual(a, b)
  • assertTrue(x)
  • assertFalse(x)
  • assertIs(a, b)
  • assertIsNot(a, b)
  • assertIsNone(x)
  • assertIsNotNone(x)
  • assertIn(a, b)
  • assertNotIn(a, b)
  • assertIsInstance(a, b)
  • assertNotIsInstance(a, b)
0.2s
Python
# Examples of unittest module
import unittest

class TestListMethods(unittest.TestCase):
    """
    Python list methods:
    https://docs.python.org/3/tutorial/datastructures.html
    """
    def test_append(self):
        x = [1, 2, 3]
        x.append(10)
        self.assertTrue(x, [1, 2, 3, 10])

    def test_count(self):
        cars = ['Mercedes', 'Lexus', 'Ford', 'BMW', 'Ferrari', 'Honda', 'Toyota', 'Ford']
        self.assertEqual(cars.count('Ford'), 2)

    def test_pop(self):
        fruits = ['apple', 'orange', 'tangerine', 'pineapple']
        self.assertEqual(fruits.pop(), 'pineapple')

    def test_reverse(self):
        music = ['jazz', 'r and b', 'rock and roll', 'edm']
        self.assertNotEqual(music.reverse(), music)

    def test_is_not(self):
        x = []
        y = [1]
        self.assertIsNot(x, y)

    def test_count_equal(self):
        a = [2, 4, 6]
        b = [6, 2, 4]
        self.assertCountEqual(a, b)

6.1. Pytest module

pytest is a framework that makes it easy to write small tests. Compared to unittest:

  • Detailed info on failing assert statements
  • No need to remember self.assert.
  • Able to run unittest and nose test suites out of the box
  • Strong plugin architecture. Has 315+ external plugins.

Installing pytest:

pip3 install -U pytest
pytest --version
Julia

In PyCharm: File -> Settings -> Tools -> Python Integration Tools -> Default test runner -> pytest

7. OOP Concepts in Python

7.1. Famous 'Dog' example

0.4s
Python
from random import choice
import fractions
import numpy as np # for float ranges

class Dog:
    def __init__(self):
        self.height = None
        self.weight = None
        self.life_expectancy = []
        self.temperament = []
        self.group = None
        self.akc_popularity = fractions.Fraction()


class AiredaleTerrier(Dog):
    """
    Inheritance: AiredaleTerrier inherits
    from the Dog class.
    """
    def __init__(self):
        self.height = '{} inches'.format(23)
        self.weight = [weight for weight in range(50, 70)]
        self.life_expectancy = [life for life in range(11, 14)]
        self.temperament = ['friendly', 'clever', 'courageous']
        self.group = 'Terrier Group'
        self.akc_popularity = fractions.Fraction(60, 193)


class BichonFrise(Dog):
    """
    Inheritance: BichonFrise inherits
    from the Dog class.
    """
    def __init__(self):
        self.height = list(np.arange(9.5, 11.5, 1.0))
        self.weight = [weight for weight in range(12, 18)]
        self.life_expectancy = [life for life in range(14, 15)]
        self.temperament = ['playful', 'curious', 'peppy']
        self.group = 'Non-Sporting Group'
        self.akc_popularity = fractions.Fraction(46, 193)


class Chihuahua(Dog):
    """
    Inheritance: Chihuahua inherits
    from the Dog class.
    """
    def __init__(self):
        self.height = [height for height in range(14, 16)]
        self.weight = [weight for weight in range(1, 6)]
        self.life_expectancy = [life for life in range(14, 16)]
        self.temperament = ['charming', 'graceful', 'sassy']
        self.group = 'Toy Group'
        self.akc_popularity = fractions.Fraction(33, 193)


class Rottweiler(Dog):
    """
    Inheritance: Rottweiler inherits
    from the Dog class.
    """
    def __init__(self):
        self.height = [24, 25, 26, 27]
        self.weight = [weight for weight in range(95, 135)]
        self.life_expectancy = [9, 10]
        self.group = 'Working Group'
        self.akc_popularity = fractions.Fraction(8, 193)


class MyDog(Rottweiler):
    """
    Inheritance: MyDog inherits
    from Rottweiler class. It also
    adds additional functionality
    not found in the Dog class
    """

    def __init__(self):
        super().__init__()  # calls the superclass constructor

    def my_dog_hobbies(self):
        return ['frisbee', 'hikes', 'eating']

    def favorite_treat(self):
        return 'apples'

    def favorite_dog_park(self):
        return 'Fort Woof'


jack = MyDog() # instance of MyDog
print(choice(jack.height))
print(choice(jack.weight), 'lbs')
print(choice(jack.life_expectancy))
print(jack.group)
print(jack.akc_popularity)
print(jack.my_dog_hobbies())
print(jack.favorite_treat())
print(jack.favorite_dog_park())

# polymorphism, greek for 'many forms'
# There's many types of dogs

bella = AiredaleTerrier()
molly = BichonFrise()
charlie = Chihuahua()
rocky = Rottweiler()

7.2. Another famous example: Cars

0.4s
Python
from random import choice


class Car:
    """
    This class models a car in python.
    """
    def __init__(self, year, make, model):
        """
        Initializes the state of the car
        object.
        year: the year the car was manufactured.
        make: the brand of the vehicle.
        model: the name used by the manufacturer.
        """
        self.year = year
        self.make = make
        self.model = model
        self.speed = 0
        self.colors = ['white', 'silver', 'black', 'grey',
                       'blue', 'red', 'brown', 'green']

        self.car_color = choice(self.colors)

    def get_year(self):
        return self.year

    def get_make(self):
        return self.make

    def accelerate(self, amount=5):
        x = amount
        if self.speed < 300 and x < 60:
            self.speed += amount
        else:
            raise ValueError('Invalid Amount')

    def hit_brakes(self, amount=5):
        x = amount
        if self.speed > 0 and x < 60:
            self.speed -= amount
        else:
            raise ValueError('Invalid Amount')

    def is_stopped(self):
        if self.speed == 0:
            return True
        return False

    def is_moving(self):
        if self.speed > 0:
            return True
        else:
            return False

    def get_color(self):
        return self.car_color

    def speedometer(self):
        return '{} mph'.format(self.speed)


a = Car('2010', 'Honda', 'Civic Hatchback')
print(a.speedometer())
print(a.is_moving())
print(a.is_stopped())
a.accelerate()
a.accelerate()
print(a.speedometer())
print(a.year)
print(a.get_color())
a.hit_brakes(10)
print(a.speedometer())

8. Regular Expressions Patterns

0.4s
Python
import re

# Simple demo of regexes

print('Simple Demo of Regexes')
print('-----------------------')

phrase = 'Learn how regular expressions work in python.'
match = re.search('python', phrase)
if match:
    print('A match is found starting at {}'
          ' and ending at {}'.format(match.start(), match.end()))
else:
    print('No match found!')

start = match.start()   # finds where key starts at in string
end = match.end()       # finds where key ends in string
print(phrase[start:end])    # python
print()

# Regex functions
# ---------------
# search(pattern, string, flags=0) -> scans the ENTIRE string for a match
# match(pattern, string, flags=0)  -> returns a match if 0 or more characters at the BEGINNING of string matches the regex
# fullmatch(pattern, string, flags=0) -> returns a match if the whole string matches the regex
# split(pattern, string, maxsplit=0, flags=0) -> split string by the pattern
# findall(pattern, string, flags=) -> returns non overlapping matches of pattern in string

print('Regex functions')
print('---------------')
print()

the_eagle_poem = """
He clasps the crag with crooked hands;

Close to the sun in lonely lands,

Ring'd with the azure world, he stands.

 
The wrinkled sea beneath him crawls;

He watches from his mountain walls,

And like a thunderbolt he falls.
"""

find_word = re.search('azure', the_eagle_poem) # <_sre.SRE_Match object; span=(92, 97), match='azure'>
print(find_word)

print(re.match('walls', the_eagle_poem))    # None
print(re.match('', the_eagle_poem))         # <_sre.SRE_Match object; span=(0, 0), match=''>
print(re.fullmatch(the_eagle_poem, the_eagle_poem))  # <_sre.SRE_Match object; span=(0, 227) ...>
print(re.split(';', the_eagle_poem))                 # ['\nHe clasps the crag with crooked hands', "\n\nClose to the sun in lonely lands...]
print(re.findall('the', the_eagle_poem))

# Matching single characters
# --------------------------
print()
phrase = 'abcdefghijklmnopqrstuvwxyz'
capital_letters = 'ABCDEFGHABCDEFGHABCDEFGH'
print('Matching Characters')
print('-------------------')
print(re.search('h', phrase))           # <_sre.SRE_Match object; span=(7, 8), match='h'>
print(re.search('b', capital_letters))  # None
print(re.search('b', capital_letters, re.IGNORECASE))   # <_sre.SRE_Match object; span=(1, 2), match='B'>
print(re.findall('C', capital_letters))     # ['C', 'C', 'C']

alpha_pattern = '0123456789abcdefgh'

print(re.search('5', alpha_pattern))    # <_sre.SRE_Match object; span=(5, 6), match='5'>
print(re.search('a', alpha_pattern))    # <_sre.SRE_Match object; span=(10, 11), match='a'>

alpha_pattern_1 = '[0-9][a-z]'      # any digit or lowercase letter
print(re.match(alpha_pattern_1, '9'))   # None

print(re.search('[a-z]', '9920202022j22929'))   # <_sre.SRE_Match object; span=(10, 11), match='j'>
print(re.search('[A-Z]', 'abcdefghijklmn83nOjsksZ'))    # <_sre.SRE_Match object; span=(17, 18), match='O'>
print(re.search('[!@#$%^&*()-+{}[]|\;"<>?', 'zvgsggs272292hkOwuyeg%ss'))   # <_sre.SRE_Match object; span=(21, 22), match='%'>
print(re.search('[a-zA-Z]', '22838828289020932;/asksk'))    # <_sre.SRE_Match object; span=(19, 20), match='a'>

# verifies a sequence of characters in a certain order

print(re.search('[a-z]{11}', '2517abcd17171179Abs20abracadabra2298'))  # <_sre.SRE_Match object; span=(21, 32), match='abracadabra'>
print(re.search('[a-z]{1,5}', '2517abcde17171179'))  # <_sre.SRE_Match object; span=(4, 9), match='abcde'>
print(re.search('[a-z]{1,5}[0-9]{3}', 'c999'))  # <_sre.SRE_Match object; span=(0, 4), match='c999'>
print(re.search('[a-z]{1,5}[0-9]{3}', 'd17'))  # None. Why?
print()

# Common Regex Character Classes
# ------------------------------
# \d -> any digit
# \D -> any non digit
# \w -> any word
# \W -> any non alphanumeric character

print('Common Regex Character Classes and Repetitions ')
print('----------------------------------------------')

print(re.search('\d', 'jsjjsk273829BHAja'))  # <_sre.SRE_Match object; span=(1, 2), match='2'>
print(re.search('\d\d', '2j8k2c8c34m3ma1'))  # <_sre.SRE_Match object; span=(8, 10), match='34'>
print(re.search('\d{3}-\d{3}-\d{4}', '230-392-9327'))   # <_sre.SRE_Match object; span=(0, 12), match='230-392-9327'>

# matches any alphanumeric character and the underscore
print(re.search('\w', ';\';,.,.,.283jsns9'))    # <_sre.SRE_Match object; span=(9, 10), match='2'>
print(re.search('\w\w\w', '9d1'))   # <_sre.SRE_Match object; span=(0, 3), match='9d1'>

# Combining the \d and \w character classes:
print(re.search('\w\d\w\d', '_0_0'))    # <_sre.SRE_Match object; span=(0, 4), match='_0_0'>
print()


# Common Regex Symbols
# ------------------------------
# * -> 0 or more repetitions
# + -> 1 or more repetitions
# ? -> 0 or 1 repetitions of the proceeding
# . -> matches any character except for a newline
# $ -> matches the end of the string, or just before the newline
# ^ -> matches the start of the string


print('Common Regex Symbols ')
print('----------------------')

# the * operator matches 0 or more repetitions
print(re.search('\d*', '28392202'))     # <_sre.SRE_Match object; span=(0, 8), match='28392202'>

# the + operator matches 1 or more repetitions
print(re.search('aba+', 'abaaaaaa'))    # <_sre.SRE_Match object; span=(0, 8), match='abaaaaaa'>

# the ? causes the regex to match 0 or 1 repetitions of the preceding
print(re.search('abc?', 'ab'))    # ab validates
print(re.search('abc?', 'abc'))   # abc validates. what about ac or bc?

# the . matches any character
print(re.search('.{3}', '/,@'))   # <_sre.SRE_Match object; span=(0, 3), match='/,@'>

# $ matches just before the end of newline
print(re.search('^\d\d\d$', '278'))     # <_sre.SRE_Match object; span=(0, 3), match='278'>


# $ Matches just before the end of the string.
# If the search key appears before the end of the string, then None returns.
# It makes way more sense with a little code.

print(re.search('zo', 'zoey'))      # <_sre.SRE_Match object; span=(0, 2), match='zo'>
print(re.search('zo$', 'zoey'))     # None
print(re.search('zo$', 'hey zo'))   # <_sre.SRE_Match object; span=(4, 6), match='zo'>
print(re.search('zo$', 'Hey zo! What\'s cracking?'))  # None
print()

# ^ matches the start of the string
print(re.search('^Hi', 'Hello, Hi'))    # None
print(re.search('^Hi', 'Hi Hello'))     # <_sre.SRE_Match object; span=(0, 2), match='Hi'>
print()

# GROUPING
# --------
# [] -> a set of characters
# |  -> matches A or B
# () -> matches the regex inside the parentheses


print('GROUPING')
print('--------')
print(re.search('[a-z][A-Z][0-9][\w]', 'aB6H'))     # <_sre.SRE_Match object; span=(0, 4), match='aB6H'>
print(re.search('[a-z]|[0-9]|[>]', 'HAKSKS6,./?'))  # <_sre.SRE_Match object; span=(6, 7), match='6'>
print(re.search('(aab)(bbc)', 'aabbbc'))            # None

9. Simple Beautiful Soup Tutorial

pip install beautifulsoup4 requests lxml
2.7s
Python
###############################################
# Simple BS4 tutorial
# -------------------
#
# Learn the basics of parsing with bs4
# by parsing sightseeingpass:
# https://www.sightseeingpass.com/en/new-york
#
# By Doug Purcell
# http://www.purcellconsult.com
#
###############################################

import requests
from bs4 import BeautifulSoup
from requests import RequestException, HTTPError, ConnectionError, URLRequired, TooManyRedirects
import lxml

def download(url, tries=3):
    """
    This function downloads a site using request
    and also has some functionality in place to
    catch exceptions and do retries if the script
    didn't work.
    """

    # creates a user agent in requests
    headers = requests.utils.default_headers()
    headers.update({'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0'})
    try:
        site = requests.get(url, headers=headers)
        soup = BeautifulSoup(site.text, 'html.parser')
    except (RequestException, HTTPError, ConnectionError, URLRequired, TooManyRedirects) as e:
        print('Download error: {}'.format(e))
        if tries > 0:
            # recursive call until tries is 0
            return download(url, tries - 1)
        soup = None
    return soup


site = download('https://www.sightseeingpass.com/en/new-york')

prettify = site.prettify()
# print(prettify)

print('---- title tag in page ----')
print(site.title)

print()
print('---- title tag string -----')
print(site.title.string)
print()

print('---- title parent name ----')
print()
print(site.title.parent.name)
print()

print('----- body tag -----')
print(site.body)
print()

print('----- meta tag -----')
print(site.meta)
print()

# gets all of the script tags
print('----- script tags -----')
script_tags = site.find_all('script')
print(script_tags)
print('--- script tag ends ---')

# gets all ul tags
print('----- ul tags -----')
ul_tags = site.find_all('ul')
print(ul_tags)
print('----- ul tags end -----')
print()

# gets all of the li tags
print('----- li tags -----')
li_tags = site.find_all('li')
print(li_tags)
print('----- li tags ends -----')
print()

# gets all of a tags
print('----- a tags ----- begin')
a_tags = site.find_all('a')
print(a_tags)
print('----- a tags ----- end')

# gets all of the p tags
print('----- p tag ------')
p_tag = site.find_all('p')
print(p_tag)
print('-----p tag ends ------')
print()

# get all of the img tags
print('----- img tag ------')
img_tag = site.find_all('img')
print(img_tag)
print('----- img tag ends ------')
print()

# gets all of the button tags
print('----- button tag ------')
button_tag = site.find_all('button')
print(button_tag)
print('----- button tag ends ------')
print()

# div tag
print('----- div tag ------')
div_tag = site.find_all('div')
print(div_tag)
print('----- div tag ends ------')
print()

# span tag
print('----- span tag -----')
span_tag = site.find_all('span')
print(span_tag)
print('----- span tag end -----')
print()

# do you see a pattern on how to get all of a certain html tag?

# Counting tags in bs4
# ---------------------------
# count number of <br /> tags
# count number of i tags
# count the number of u tags
# count the number of b tags
# count the number of div tags

br_count = 0
for br_tag in site.find_all('br'):
    br_count += 1

i_tag_count = 0
for i_tag in site.find_all('i'):
    i_tag_count += 1

u_tag_count = 0
for u_tag in site.find_all('u'):
    u_tag_count += 1

b_tag_count = 0
for b_tag in site.find_all('b'):
    b_tag_count += 1


print('---- Div Tag Count ----')
div_tag_count = 0
div_count = len(site.find_all('div'))

print('There\'s {} br tags'.format(br_count))
print('There\'s {} i tags'.format(i_tag_count))
print('There\'s {} u tags'.format(u_tag_count))
print('There\'s {} b tags'.format(b_tag_count))
print('There\'s {} div tags'.format(div_count))


# refining our bs4 scraps
# -----------------------
# most scraps aren't this simple
# sometimes we get data that we don't want
# therefore, we need ways to extract only certain parts


# find method
# ------------
# function signature: find(name, attrs, recursive, string, **kwargs)
# details: https://www.crummy.com/software/BeautifulSoup/bs4/doc/#find
# compared to find_all it just looks for the first result. find_all
# scans the entire document looking for results. I.e, tags that
# occur once like body, html, head, title, etc.
# Also, find returns the result, while find_all returns a list of results

print('----- The header -----')
header = site.find('header')
print('The header is {}'.format(header))
print('----- The header end -----')
print()

print('----- div slice -----')
div_tags = site.find_all('div')
print(div_tags[1:4])
print('----- div slice end -----')
print()

# select
# ------
# css selectors
# select, match, filter using modern CSS selectors
# learn about the api: https://facelessuser.github.io/soupsieve

print('----- regular match with css selectors -----')
print(site.select('title'))
print()

print('----- find tags beneath other tags -----')
top_10_nyc = site.select('p span')
print(top_10_nyc)

# how to refine so i get the span tag with the class attribute...
# of menu-hover-bar--red?
top_10_nyc = site.select(".menu-hover-bar--red")[0]
print(top_10_nyc)

# how can we get the text between the tags?
print(top_10_nyc.get_text())

# what's a second way that I can get text between tags?
# get the first element from the contents
print(top_10_nyc.contents[0])

# what's a 3rd way :-)?
# find the next tag, use next attribute
print(top_10_nyc.next)

# jeez, what's a fourth way?
# use .string
print(top_10_nyc.string)
print()

print('----- find tags directly beneath other tags -----')
site_lists = site.select('p > span')
for x, y in enumerate(site_lists):
    print(site_lists[x].contents[0])
print()

print('----- Address -----')
contact_us = site.select('.desk-footer__contact-us p')
print(contact_us[0].get_text())

print('----- Get the a tags in the footer -----')
footer_links = site.select('#linksMoreInformation a')
for links in footer_links:
    print(links)
print()
print('----- Get the href tags in the footer -----')
for links in footer_links:
    print(links['href'])
print()

print('----- Get the social media links -----')
for social_links in site.select('.social-bar li a'):
    print(social_links['href'])

print()
print('----- get all of the links on the site -----')
for web_links in site.find_all('a', {'href': True}):
    print(web_links['href'])


# understanding parents and siblings
# ----------------------------------

# parents is needed if you need to work your way up a tree
# i.e, start somewhere and then start working your way up
print()
print('----- parents -----')
print()

tag = site.find('head')
print(tag.find_parents('html'))
print()

# gets elements that's side by side
print('----- siblings -----')
div_class = site.find('div')
print(div_class.find_next_sibling())

10. HTTP Requests Fundamentals in Python

pip install httplib2
2.1s
Python
########################################
# HTTP requests fundamentals in python
# -------------------------------------
#
# Learn the various ways to make HTTP/1.1 requests
# in python through code examples.
#
# requests: https://pypi.org/project/requests
# urllib3: https://urllib3.readthedocs.io/en/latest
# urllib2: https://docs.python.org/2/library/urllib2.html
# httplib2: https://github.com/httplib2/httplib2
#
# By Doug Purcell
# http://www.purcellconsult.com
#
##########################################

import requests
import urllib
from urllib.request import urlopen
import urllib3
import httplib2


# Requests Overview
# -----------------
# Fully supports a restful API
# get, post, put, delete, methods
# international domains and urls
# keep-alive & connection pooling (uses urllib3 for this)
# browser-style SSL verification

# making a simple HTTP/1.1 request

wiki = requests.get('https://en.wikipedia.org/wiki/Main_Page')

print(wiki.status_code)  # checks the status codes: 200

print(requests.codes['temporary_redirect'])  # 307

# after a server returns the response you want, can collect content

t = wiki.text       # response in bytes
c = wiki.content    # response in Unicode

print(dir(wiki))    # see all of the cool functionality you can do!
print(wiki.headers['Content-Type'])

# The urllib module
# ------------------
# URL Handing Modules: https://docs.python.org/3/library/urllib.html
# contains several modules for working with URLS such as
# urllib.request, urllib.error, urllib.parse, and urllib.robotparser

# returns the URL of the resource received
url = urllib.request.urlopen('https://www.gocomics.com/comics/popular')

# returns URL of the resource retrieved
link = url.geturl()

# returns meta info of the page like headers
code = url.info()

# returns the HTTP status of the response
status = url.getcode()

print(url)
print(link)
print(code)
print(status)

# The urllib2 module
# ------------------
# A module that's been split across various modules
# in python3 named urllib.request and urllib.error.
# since the urllib2 module has been split across several modules,
# must do the following: from urllib.request import urlopen

site = urlopen('https://www.latimes.com')
content = ''
for text in site:
    content += str(text)

# The urllib3 module
# ------------------
# A powerful HTTP client for python. Some of its features:
# Thread safety
# Connection pooling
# Client-side SSL/TLS verification
# File uploads with multipart encoding

http = urllib3.PoolManager()    # needed to make requests
r = http.request('GET', 'http://www.yahoo.com')
print(r.data.decode('utf-8'))

h = httplib2.Http('.cache')
(resp_headers, content) = h.request('http://www.example.org', 'GET')

h = httplib2.Http(".cache")
h.add_credentials('name', 'password')
(resp, content) = h.request("https://example.org/chapter/2",
                            "PUT", body="This is text",
                            headers={'content-type':'text/plain'} )

# Why so many options for making HTTP requests?
# There are many talented developers who feel they can
# create a better solution then the other ones.

11. Scrappy Spider

conda install -c conda-forge scrapy
import scrapy
class BasicSpider(scrapy.Spider):
    name = 'basic'
    allowed_domains = ['web']
    start_urls = ['https://sfbay.craigslist.org/search/sfc/apa']

    def parse(self, response):
        self.log("titles: {}".format(response.xpath('//span/text()').extract()))
        self.log("date: {}.".format(response.xpath('//*[@class="result-date"][1]/text()').extract()))
        self.log("urls: {}".format(response.xpath('//*[@class="result-title hdrlnk"][1]/@href').extract()))
        self.log("price: {}".format(response.xpath('//*[@class="result-price"][1]/text()').extract()))
        self.log("description is {}".format(response.xpath('//*[@class="result-hood"][1]/text()').extract()))

12. Generators in Python

0.5s
Python
##########################################
# Generators in python
# ----------------------
#
#
#
# By Doug Purcell
# http://www.purcellconsult.com
#
##########################################

from random import choice
from string import ascii_letters, digits

symbols = '★☺⁂♬ϟ⌚'
# option 1
option_1 = []
for x in symbols:
    option_1.append(ord(x))

# option 2
option_2 = [ord(x) for x in symbols]

# option 3 generator expression

genexpr = (ord(x) for x in symbols)
print(option_1)
print(option_2)
print(next(genexpr))
print(next(genexpr))
print(next(genexpr))

# Option 2 is still easy to understand plus only contains one line of code compared to 3 lines in option 1.
# Also, a list comprehensions intent is clear. It only builds a list. A for loop can do a ton of stuff, compute values, count items, etc.

# list comprehensions vs map and filter
# list comprehensions can emulate the logic of maps and filter

message = 'python is a fine language'
output_1 = [ord(x) for x in message if ord(x) > 110]

# maps and filter
output_2 = list(filter(lambda x: x > 110, map(ord, message)))
print(output_1)
print(output_2)

print()
symbols = '★☺⁂♬ϟ⌚'
list_comp = [ord(x) for x in symbols]
genexpr = (ord(x) for x in symbols if ord(x) > 110)

print(list_comp)
print(genexpr)
print(next(genexpr))
print(next(genexpr))
print(next(genexpr))


def forever(start=1, step=5.5):
    while True:
        start = (start * step)**3
        yield start


forever()

# simple generator example

message = 'hello'
for char in message:
    print(char)

# if we had to implement this with a while loop, it looks something like..

it = iter(message)
while True:
    try:
        print(next(it))
    except StopIteration:
        del it
        break


def gen_12345():
    for x in range(5):
        yield x


print(next(gen_12345()))
print(next(gen_12345()))


class Password:

    def __init__(self, length=8):
        self.password = ''
        i = 0
        if length >= 8 and length < 21:
            chars = ascii_letters + digits
            while i < length:
                self.password += choice(chars)
                i += 1

    def __iter__(self):
        return self

    def __next__(self):
        for ch in self.password:
            yield ch


secret = Password()
print(secret.password)

it = iter(secret)
print(it)
print(next(it))
print(next(it))


# iterators in python
class SimpleNumber:
    def __init__(self, start=0):
        self.start = start

    def __iter__(self):
        return self

    def __next__(self):
        for x in range(self.start):
            yield x


simple = SimpleNumber()


it = iter(simple)
print(it.__next__())

print(next(it))
print(next(it))

13. Example projects

13.1. ATM Machine

7.0s
Python
###########################################
# ATM Machines
# ------------
# Models an ATM machine in python. Contains the
# following functions:
#
# deposit: adds money to an account.
# withdrawal: withdraws money from an account.
# check_balance: check the current account balance.
# get_transactions: shows the date and amount of recent transaction.
# get_withdrawals: returns the cash.
# pin: get your pin number.
# get_name: get the customer's name.
#
# By Doug Purcell
# http://www.purcellconsult.com
#
#############################################

import datetime


class Atm:
    """
    Models an ATM machine in python using
    oop.
    """

    def __init__(self, name, pin):
        self.name = input("What's your name? ")
        self.name = self.name.capitalize()
        print('Welcome to Your Virtual ATM {} '.format(self.name))
        self.amount = 0
        self.transactions = dict()
        self.withdrawals = dict()
        self.pin = ''
        if pin.isdigit() and len(pin) == 4:
            self.pin = pin
        else:
            raise ValueError('Invalid Pin Number')
        self.customer_account = dict()
        self.customer_account.update(name=self.name)
        self.customer_account.update(pin=self.pin)

    def deposit(self, cash):
        """
        Deposits money into an account as long
        as the deposit is less than $1000 and greater
        than $0.
        """
        if cash > 0 < 1000:
            self.amount += cash
            date_stamp = str(datetime.datetime.now())
            self.transactions.update(transaction=[date_stamp, cash])
        else:
            print('Transaction Declined.')

    def withdraw(self, cash):
        """
        withdraw money from the atm machine.
        """
        if cash > 0 < 500:
            if cash > self.amount:
                print('Insufficient funds in account')
            elif cash < 1:
                print('Invalid amount. Enter at least $1')
            else:
                self.amount -= cash
                date_stamp = str(datetime.datetime.now())
                self.withdrawals.update(withdrawal=[date_stamp, -cash])

    def check_balance(self):
        """
        returns the current balance
        of the account.
        """
        return self.amount

    def get_transactions(self):
        """
        returns the account details.
        """
        return self.transactions

    def get_withdrawals(self):
        """
        returns the recent withdrawal.
        """
        return self.withdrawals

    def get_pin(self):
        """
        gets the pin
        """
        return self.pin

    def get_name(self):
        """
        returns the name of the customer.
        """
        return self.name


jack = Atm('Jack', '3282')
jack.deposit(100)
print(jack.get_transactions())
jack.deposit(200)
print(jack.get_transactions())
jack.withdraw(10)
print(jack.get_withdrawals())
jack.deposit(100)
print(jack.get_transactions())
jack.withdraw(100)
print(jack.get_withdrawals())
print(jack.get_pin())
print(jack.get_name())

jill = Atm('Jill', '29321')

henry = Atm('henry', '3821')
henry.deposit(1000)
print(henry.get_transactions())
henry.withdraw(2000)

13.2. California Lottery

6.2s
Python
##########################################
# Get practice for the California lottery!
# See list of California Lottery Results:
# https://www.lotteryusa.com/california
#
# This script models the following:
# Daily 3
# Daily 4
#
# By Doug Purcell
# http://www.purcellconsult.com
#
#
###########################################

from random import randint
from time import sleep

daily_3 = input("Would you like to play the Daily 3? Enter 'y' for yes or 'n' for no ")

# normalizes the text
daily_3 = daily_3.lower()

if daily_3 == 'y':
    lucky_num_1 = randint(0, 9)
    lucky_num_2 = randint(0, 9)
    lucky_num_3 = randint(0, 9)
    lucky_nums = [lucky_num_1, lucky_num_2, lucky_num_3]
    user_input_1 = int(input('Enter your lucky number #1 '))
    user_input_2 = int(input('Enter your lucky number #2 '))
    user_input_3 = int(input('Enter your lucky number #3 '))
    print('Lucky number number 1...')
    sleep(1)
    print(lucky_num_1)
    print('Lucky number number 2...')
    sleep(1)
    print(lucky_num_2)
    print('Lucky number number 3...')
    sleep(1)
    print(lucky_num_3)
    sleep(1)

    print('The Daily 3 Are:', lucky_nums)

    if user_input_1 == lucky_num_1 and user_input_2 == lucky_num_2 and user_input_3 == lucky_num_3:
        print('You won the daily 3!')
    else:
        print('You didn\'t win the lucky 3 :-(')
else:
    pass

daily_4 = input("Would you like to play the Daily 4? Enter 'y' for yes or 'n' for no ")

# normalizes the text
daily_4 = daily_4.lower()

if daily_4 == 'y':
    lucky_num_1 = randint(0, 9)
    lucky_num_2 = randint(0, 9)
    lucky_num_3 = randint(0, 9)
    lucky_num_4 = randint(0, 9)
    lucky_nums = [lucky_num_1, lucky_num_2, lucky_num_3, lucky_num_4]
    user_input_1 = int(input('Enter your lucky number #1 '))
    user_input_2 = int(input('Enter your lucky number #2 '))
    user_input_3 = int(input('Enter your lucky number #3 '))
    user_input_4 = int(input('Enter your lucky number #4 '))
    print('Lucky number number 1...')
    sleep(1)
    print(lucky_num_1)
    print('Lucky number number 2...')
    sleep(1)
    print(lucky_num_2)
    print('Lucky number number 3...')
    sleep(1)
    print(lucky_num_3)
    sleep(1)
    print('Lucky number number 4...')
    sleep(1)
    print(lucky_num_4)

    print('The Daily 4 Are:', lucky_nums)

    if user_input_1 == lucky_num_1 and user_input_2 == lucky_num_2:
        if user_input_3 == lucky_num_3 and user_input_4 == lucky_num_4:
            print('You won the daily 3!')
        else:
            print('Didn\'t win the lucky 4 :-(')
    else:
        print('Didn\'t win the lucky 4 :-(')

13.3. The Dice Simulator

9.5s
Python
#######################################
# A simple dice rolling simulator.
# A simple program that models dice
# rolling in python.
#
#
# By Doug Purcell
# http://www.purcellconsult.com
#
#######################################


from random import randint
from time import sleep

number_of_rolls = int(input('How many rounds you want to play? '
                            'Enter a number from 1-20: '))

if number_of_rolls < 0 or number_of_rolls > 20:
    print('Invalid input. Exiting program...')
    exit(0)

correct_guesses, tries = 0, 0

dice_numbers = {
    1: 0,
    2: 0,
    3: 0,
    4: 0,
    5: 0,
    6: 0,
}

while tries < number_of_rolls:

    print('round:', tries)
    your_guess = int(input('Roll the dice. Enter a number from 1-6... '))
    if your_guess < 0 or your_guess > 6:
        print('Invalid input. Must enter numbers within range of 1...6')
        print('Exiting...')
        break
    print('Dice rolling...')
    sleep(3)
    dice_result = randint(1, 6)
    if your_guess == dice_result:
        print('You win! The dice landed on', dice_result)
        correct_guesses += 1
    else:
        print('Better luck next time. Dice landed on', dice_result)

    if dice_result == 1:
        dice_numbers[1] += 1
    elif dice_result == 2:
        dice_numbers[2] += 1
    elif dice_result == 3:
        dice_numbers[3] += 1
    elif dice_result == 4:
        dice_numbers[4] += 1
    elif dice_result == 5:
        dice_numbers[5] += 1
    elif dice_result == 6:
        dice_numbers[6] += 1
    tries += 1

    if tries == number_of_rolls:
        print('Dice landed on 1:', dice_numbers[1], 'times')
        print('Dice landed on 2:', dice_numbers[2], 'times')
        print('Dice landed on 3:', dice_numbers[3], 'times')
        print('Dice landed on 4:', dice_numbers[4], 'times')
        print('Dice landed on 5:', dice_numbers[5], 'times')
        print('Dice landed on 6:', dice_numbers[6], 'times')
        print('Correct guesses: ', correct_guesses)
        print('Average of correct guesses: {}%'.format(round((correct_guesses / number_of_rolls) * 100), 3))

13.4. A Game of Conditions

4.2s
Python
###########################################################
# A Game of Conditions: Text Based Fantasy Game in Python
# --------------------------------------------------------
# This is the text based adventure game.
# It works by asking the gender of the user,
# asking them additional questions, and then modifying the
# storyline accordingly.
#
# By Doug Purcell
# http://www.purcellconsult.com
#
###########################################################


def male_adventure():
    your_name = input('Enter your name: ')
    queen_name = input('What\'s the name of your queen? ')
    kingdom = input('What\'s the name of your kingdom? ')
    your_name, queen_name, kingdom = your_name.capitalize(), queen_name.capitalize(), kingdom.capitalize()
    have_allies = input('Do you have allies? Enter "y" for yes or "n" for no. ')
    have_enemies = input('Do you have enemies? Enter "y" for yes or "n" for no. ')
    have_allies, have_enemies = have_allies.lower(), have_enemies.lower()

    if have_allies == 'y':
        paladin = input('Enter your paladin\'s name ')
        wizard = input('Enter your wizard\'s name ')
        warrior = input('Enter your warrior\'s name ')
        paladin, wizard, warrior = paladin.capitalize(), wizard.capitalize(), \
                                   warrior.capitalize()
    elif have_allies == 'n':
        pass

    if have_enemies == 'y':
        print('{} got enemies, got a lot of enemies'.format(your_name))
        villian = input('Enter your villian\'s name ')
        war_name = input('What\'s the name of your war? ')
        years = int(input('How many years did the war last? '))
        thief = input('Enter your thief\'s name ')
        evil_sorcerer = input('Enter evil sorcerer\'s name ')
        rogue = input('Enter rogue\'s name ')
        thief, evil_sorcerer, rogue = thief.capitalize(), evil_sorcerer.capitalize(), rogue.capitalize()
    elif have_enemies == 'n':
        pass

    if have_allies == 'y' and have_enemies == 'y':
        message = """
            The great {0} and his queen {1} peacefully ruled the kingdom of
            {2}. However, a great war called {3} erupted. {0}'s nemesis {4} invaded
            his kingdom. With the help of {5}, {6}, and {7}, {4} pillaged their land,
            stole precious resources, and brutally attacked their villagers.
            King {0} and Queen {1} with the help of {8}, {9}, and {10} valiantly 
            fought back and defeated {4} after {11} years of fierce fighting. Order was finally
            restored and everyone in their kingdom lived happily ever after :-).""".format(your_name, queen_name,
                                                                                           kingdom, war_name, villian,
                                                                                           thief, evil_sorcerer, rogue,
                                                                                           paladin, wizard, warrior,
                                                                                           years)
        print(message)
    elif have_allies == 'y' and have_enemies == 'n':
        message = """
            The great {0} and his queen {1} peacefully ruled the kingdom of
            {2}. With the help of {3}, {4}, and {5}, {0} and {1} were able to keep their
            kingdom safe forever. The entire kingdom of {2} lived happily ever after :-).True Story.THE END.""".format(
            your_name, queen_name,
            kingdom, paladin, wizard, warrior, kingdom)
        print(message)
    elif have_allies == 'n' and have_enemies == 'y':
        message = """
                        The great {0} and his queen {1} peacefully ruled the kingdom of
                        {2} for many years. However, one evening their nemesis {3} with the help of
                        {4}, {5}, and {6} invaded their kingdom which lead to an infamous war in {2}
                        history called {8}. This war lasted {9} years. In the end {3} and his goons pillaged the land, destroyed the villagers,
                        and usurped {0} and {1}. THE END :-(""".format(your_name, queen_name, kingdom, villian, thief,
                                                                       evil_sorcerer, rogue, kingdom, war_name, years)
        print(message)
    elif have_enemies == 'n' and have_enemies == 'n':
        message = """
            The great {0} and his queen {1} lived in the kingdom of
                        {2} for many years alone. 
            """.format(your_name, queen_name, kingdom)
        print(message)
        pass


def female_adventure():
    """This the function for the female adventure."""
    your_name = input('Enter your name: ')
    king_name = input('What\'s the name of your king? ')
    kingdom = input('What\'s the name of your kingdom? ')
    have_allies = input('Do you have allies? Enter "y" for yes or "n" for no. ')
    have_enemies = input('Do you have enemies? Enter "y" for yes or "n" for no. ')

    if have_allies == 'y':
        paladin = input('Enter your paladin\'s name ')
        wizard = input('Enter your wizard\'s name ')
        warrior = input('Enter your warrior\'s name ')

    if have_allies == 'n':
        pass

    if have_enemies == 'y':
        print('{} got enemies, got a lot of enemies'.format(your_name))
        villian = input('Enter your villian\'s name ')
        war_name = input('What\'s the name of your war? ')
        years = int(input('How many years did the war last? '))
        thief = input('Enter your thief\'s name ')
        evil_sorcerer = input('Enter evil sorcerer\'s name ')
        rogue = input('Enter rogue\'s name ')
    if have_enemies == 'n':
        pass

    if have_allies == 'y' and have_enemies == 'y':
        message = """
            The great {0} and her king {1} peacefully ruled the kingdom of
            {2}. However, a great war called {3} erupted. {0}'s nemesis {4} invaded
            her kingdom. With the help of {5}, {6}, and {7}, {4} pillaged their land,
            stole precious resources, and brutally attacked their villagers.
            Queen {0} and King {1} with the help of {8}, {9}, and {10} valiantly 
            fought back and defeated {4} after {11} years of fierce fighting. Order was finally
            restored and everyone in their kingdom lived happily ever after :-).""".format(your_name.capitalize(),
                                                                                           king_name.capitalize(),
                                                                                           kingdom.capitalize(),
                                                                                           war_name.capitalize(),
                                                                                           villian.capitalize(),
                                                                                           thief.capitalize(),
                                                                                           evil_sorcerer.capitalize(),
                                                                                           rogue.capitalize(),
                                                                                           paladin.capitalize(),
                                                                                           wizard.capitalize(),
                                                                                           warrior.capitalize(), years)
        print(message)
    elif have_allies == 'y' and have_enemies == 'n':
        message = """
            The great {0} and her king {1} peacefully ruled the kingdom of
            {2}. With the help of {3}, {4}, and {5}, {0} and {1} were able to keep their
            kingdom safe forever. The entire kingdom of {2} lived happily ever after :-).True Story.THE END.""".format(
            your_name, king_name,
            kingdom, paladin, wizard, warrior, kingdom)
        print(message)
    elif have_allies == 'n' and have_enemies == 'y':
        message = """
                        The great {0} and her king {1} peacefully ruled the kingdom of
                        {2} for many years. However, one evening their nemesis {3} with the help of
                        {4}, {5}, and {6} invaded their kingdom which lead to an infamous war in {2}
                        history called {7}. This war lasted {8} years. In the end {3} and his goons pillaged the land, destroyed the villagers,
                        and usurped {0} and {1}. THE END :-(""".format(your_name, king_name, kingdom, villian,
                                                                       thief, evil_sorcerer, rogue, kingdom,
                                                                       war_name, years)
        print(message)
    elif have_enemies == 'n' and have_enemies == 'n':
        message = """
            The great {0} and her king {1} lived in the kingdom of
                        {2} for many years alone. 
            """.format(your_name, king_name, kingdom)
        print(message)
        pass


gender = input('Enter your gender: "m" for male, "f" for female.'
               )

# converts input to lower
gender = gender.lower()
if gender == 'f':
    female_adventure()
elif gender == 'm':
    male_adventure()
else:
    print('Enter correct option or you "can\'t" play!')

13.5. Parse the cali state site

0.3s
Python
########################################
# Parse the cali state site
# -------------------------
# A simple tutorial to get us
# comfortable with parsing websites
# for specific data using BS4.
#
# By Doug Purcell
# http://www.purcellconsult.com
#
########################################

from site_downloader import download

soup = download('https://www.ca.gov')

# header text
# select is used for css selectors

print('----- header anchor text -----')
for header_text in soup.select('span.link-title'):
    print(header_text.text)
print()

# header links
print('----- header links -----')
for a_href in soup.find_all('a', 'first-level-link'):
    print(a_href['href'])

print()
print('------- h4 and h3 text --------')
print()

# Gets the text in between a h4 tag with a certain class
for h4_text in soup.find_all('h4', attrs={'class': 'title'}):
    print(h4_text.text)

# Gets the text in between a h3 tag with a certain class
for h3_text in soup.find_all('h3', attrs={'class': 'title'}):
    print(h3_text.text)


print('---- footer text ----')
print(soup.select('span'))

# h2 module headers
for h2_text in soup.select('h2.et_pb_module_header'):
    print(h2_text.text, end=' | ')
print()

print()
print('----- more footer links -----')
list_stand_out = soup.select('.list-standout')
for list_items in list_stand_out:
    for x in list_items.find_all('a'):
        print(x['href'])


print()
print('----- website image links -----')

for images in soup.find_all('img'):
    print(images['src'])


print()
print('----- footer links -----')
for footer_links in soup.find_all('ul', {'class': 'footer-links'}):
    for links in footer_links.find_all('a'):
        print(links['href'])

print()
print('----- social sharing buttons -----')
social_buttons = soup.select('.socialsharer-container')
for social_links in social_buttons:
    links = social_links.find_all('a')
    for social in links:
        print(social['href'])

print(soup.select('.NaturalImage-imag'))

13.6. Regular Expressions Lab

0.5s
Python
###########################################
# Regular Expressions Lab
# -----------------------
#
#
# By Doug Purcell
# http://www.purcellconsult.com
#
############################################

import requests
import re


def general_number(string):
    """
    This regular expression validates
    a number within this format:
    ###-###-####
    """
    phone_regex = '^\d{3}-\d{3}-\d{4}$'
    scan = re.search(phone_regex, string)
    if scan:
        print('Verified Number!')
    else:
        print('Doesn\'t validate!')


def ssn_checker(ssn):
    """
    A regex that verifies that the string entered is
    a valid social security number. The ssn number could be
    in the following formats:
    XXX-XX-XXXX or ...
    XXXXXXXXX
    """
    ssn_validator = '^\d{3}-\d{2}-\d{4}$|^\d{9}$'
    check = re.search(ssn_validator, ssn)
    if check:
        print('{} is a valid social security number'.format(ssn))
    else:
        print('{} is an invalid social security number'.format(ssn))


def email_address_checker(email):
    """
    Verifies if the user entered a valid
    email address.
    """
    email_checker = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,64}$'
    check = re.search(email_checker, email)
    if check:
        print('{} is a valid email address.'.format(email))
    else:
        print('{} is not a valid email address.'.format(email))


def song_stats(file):
    """
    This function parses a junk
    text file for valid email
    addresses.
    """
    data = ''
    vowels = '[aeiouy]'
    constants = '[bcdfghijklmnpqrstvwxz]'
    with open('imagine') as text:
        for line in text:
            data += line
        vowel_count = re.findall(vowels, data)
        constant_count = re.findall(constants, data)
        print(data)
        print(len(data))
        print(len(vowel_count))
        print(len(constant_count))


site = requests.get('https://en.wikipedia.org/wiki/Ferrari')
html = site.text
regex = re.compile(r'Ferrari')

hit = re.findall(regex, html)

print(len(hit))


print('General Number Function Tests')
print('-----------------------------')
general_number('263-328-8372')
general_number('263-328-83722')
general_number('2633288372')
general_number('263-328-8372')
print()

print('Social Security Number Tester')
print('-----------------------------')
ssn_checker('928-382')
ssn_checker('728-23-9272')
ssn_checker('728239272')
ssn_checker('542-50-4814')
ssn_checker('63236638232')


print('Email Address Checker')
# used the following test cases:
# https://blogs.msdn.microsoft.com/testing123/2009/02/06/email-address-test-cases
print('---------------------')
print()
print('Valid Email Tests')
print()

email_address_checker('email@domain.com')
email_address_checker('firstname+lastname@domain.com')
email_address_checker('email@subdomain.domain.com')
email_address_checker('firstname+lastname@domain.com')
email_address_checker('email@123.123.123.123')
email_address_checker('email@[123.123.123.123]')
email_address_checker('"email"@domain.com')
email_address_checker('1234567890@domain.com')
email_address_checker('email@domain-one.com')
email_address_checker('_______@domain.com')
email_address_checker('email@domain.name')
email_address_checker('email@domain.co.jp')
email_address_checker('firstname-lastname@domain.com')

print()
print('Invalid Email Tests')
print()

email_address_checker('plainaddress')
email_address_checker('#@%^%#$@#$@#.com')
email_address_checker('@domain.com')
email_address_checker('Joe Smith <email@domain.com>')
email_address_checker('email.domain.com')
email_address_checker('email@domain@domain.com')
email_address_checker('.email@domain.com')
email_address_checker('email.@domain.com')
email_address_checker('email..email@domain.com')
email_address_checker('あいうえお@domain.com')
email_address_checker('email@domain.com (Joe Smith)')
email_address_checker('email@domain')
email_address_checker('email@-domain.com')
email_address_checker('email@domain.web')
email_address_checker('email@111.222.333.44444')
email_address_checker('email@domain..com')

13.7. The Secret Number Guessing Game

4.0s
Python
##############################################
# The Secret Number Guessing Game
# -------------------------------
# User must guess a number within the range of 1-100.
# Once a correct guess is recorded the program prints
# game stats which includes number of tries, max and min guess,
# summation of scores, mean, and the secret number.
# If user fails to guess the correct number within the time
# frame then the program prints the correct number and stats.
#
# Game has two modes:
# -------------------
# Mode 1: User can guess an unlimited number of times.
# Mode 2: User is given a random number of tries in the range
# of 1-10.
#
# To run the program download it to your Desktop and within the
# terminal type: python guessing_game.py
#
# By Doug Purcell
# http://www.purcellconsult.com
#
###############################################

from random import randint

option = input("Do you want unlimited tries? Enter 'y' or 'n' ")
option = option.lower()

"""
Variable Declarations:
---------------------
Defining the variables that don't 
need to be reset outside of the
while loops. 
"""
the_secret_number = randint(1, 100)
number_of_tries, summation, count = 0, 0, 0
max_number, min_number = the_secret_number, the_secret_number

if option == 'y':
    while True:
        your_guess = int(input('Enter a number in the range of 1-100 '))
        if your_guess < 0 or your_guess > 100:
            print('Invalid input: Must enter within the range of 1-100')
            break
        elif your_guess > the_secret_number:
            print(your_guess, 'is bigger than the secret number ')
        elif your_guess < the_secret_number:
            print(your_guess, 'is less than the secret number ')
        number_of_tries += 1
        summation += your_guess
        if your_guess > max_number:
            max_number = your_guess
        elif your_guess < min_number:
            min_number = your_guess
        elif your_guess == the_secret_number and number_of_tries == 1:
            max_number = your_guess
            min_number = your_guess
        if your_guess == the_secret_number:
            print(your_guess, 'is the correct answer')
            print('Number of tries =', number_of_tries)
            print('Max number you guessed =', max_number)
            print('Min number you guessed =', min_number)
            print('Summation of numbers =', summation)
            print('The average of numbers =', round(summation / number_of_tries, 2))
            break

elif option == 'n':
    number_of_tries = randint(1, 10)
    print('You have', number_of_tries, 'number of tries.')
    while number_of_tries > 0:
        your_guess = int(input('Enter a number in the range of 1-100 '))
        if your_guess < 0 or your_guess > 100:
            print('Invalid number: Must be in range of 1-100')
            break
        print(number_of_tries - 1, 'tries left!')
        if your_guess > the_secret_number:
            print(your_guess, 'is bigger than the secret number ')
        elif your_guess < the_secret_number:
            print(your_guess, 'is less than the secret number ')
        count += 1
        summation += your_guess
        number_of_tries -= 1

        """
        Takes care of the special case in which
        the user only gets one chance to
        guess the number.
        """
        if number_of_tries == 0 and count == 1:
            max_number = your_guess
            min_number = your_guess
        if your_guess > max_number:
            max_number = your_guess
        elif your_guess < min_number:
            min_number = your_guess

        """
        Prints the user stats. 
        ----------------------
        The first branch computes the stats if the user 
        guesses the correct number before number_of_tries 
        is equal to 0. The elif branch computes the stats if 
        the user doesn't guess the correct number within
        the allocated number of tries.
        """
        if your_guess == the_secret_number:
            print(your_guess, 'is the correct answer')
            print('You win!')
            print('Number of tries =', count)
            print('Max number you guessed =', max_number)
            print('Min number you guessed =', min_number)
            print('Summation of numbers =', summation)
            print('The average of numbers =', round(summation / count, 2))
            break
        elif your_guess is not the_secret_number and number_of_tries == 0:
            print('Good try :-)!')
            print('Secret number is ', the_secret_number)
            print('Number of tries =', count)
            print('Max number you guessed =', max_number)
            print('Min number you guessed =', min_number)
            print('Summation of numbers =', summation)
            print('The average of numbers =', round(summation / count, 2))

else:
    print('Invalid option! Program terminates...')

13.8. Sports betting

4.7s
Python
#####################################################
# A sports betting script written in python.
# What the script handles:
#
# American odds formula:
# Decimal odds formula:
# Percentage odds formula:
# Implied probability formula:
#   + 1P = 100 / (odd + 100)
#   - 1P = (-1 x odd) / ((-1 x odd) + 100)
#
#
# By Doug Purcell
# http://www.purcellconsult.com
#
#
#####################################################

from fractions import Fraction


def odds_calculator(american_odds, amount=100):
    """provides the amount to win and the payout."""

    if american_odds > 0:

        fractional_odds = Fraction(american_odds, 100)

        to_win = float(fractional_odds * amount)
        payout = float(to_win + amount)
        decimal_odds = 1 + fractional_odds
        decimal_odds = float(decimal_odds)
        implied_prob = round(100 / (american_odds + 100), 3)
        implied_prob *= 100
        print('-----------------------')
        print(
              f'To win: {to_win} \n'
              f'Payout: {payout} \n'
              f'American odds: {american_odds} \n'
              f'Fractional odds: {fractional_odds} \n'
              f'Decimal odds: {decimal_odds} \n'
              f'Implied probability: {implied_prob} '
              )
    else:
        american_odds = (american_odds)
        fractional_odds = abs(Fraction(100, american_odds))
        to_win = int(amount * fractional_odds)
        payout = int(to_win + amount)
        decimal_odds = 1 + fractional_odds
        implied_prob = (-1 * american_odds)
        implied_prob = round(implied_prob / ((-1 * american_odds) + 100),3)
        implied_prob *= 100
        print(
            f'To win: {to_win} \n'
            f'Payout: {payout} \n'
            f'American odds: {american_odds} \n'
            f'Fractional odds: {fractional_odds} \n'
            f'Decimal odds: {decimal_odds} \n'  
            f'Implied probability: {implied_prob} '
        )



print('Welcome to the odds calculator: ')
odds = int(input('Enter the odds '))
wager = int(input('Enter wager (bet amount)'))
print(f'Bet {wager}')
odds_calculator(odds, wager)

13.9. Testing lab in python

0.2s
Python
###############################################
# Testing lab in python
# ----------------------
# Learn how to test various functions
# and methods in python using the unittest,
# pytest, nose, doctest, mock, and hypothesis.
#
# Goal. Get it to work in unittest.
#
#
# By Doug Purcell
# http://www.purcellconsult.com
#
###############################################

import unittest


"""
using unittest in python:
https://docs.python.org/3/library/unittest.html
"""

class TestPythonFunctions(unittest.TestCase):
    """
    This class is used to test some of the functions
    in the builtin python library:
    https://docs.python.org/3/library/functions.html
    """

    def test_abs(self):
      self.assertEqual(1010, abs(-1010))

    def test_abs_not_equal(self):
        self.assertNotEqual(-1100, abs(-1100))

    def test_bin(self):
        self.assertEqual('0b1010', bin(10))

    def test_bool(self):
        self.assertEqual(True, 5 > 3)

    def test_callable(self):
        def fun():
            return 'YEAH BOI!!!'
            self.assertEqual(True, callable(self.fun))

    def test_chr(self):
        self.assertEqual(chr(91) + chr(93), '[]')

    def test_dict(self):
        self.assertEqual(dict(a=10, b=10, c=30, d=40, e=50), {'a': 10, 'b': 10, 'c': 30, 'd': 40, 'e': 50})

    def test_divmod(self):
        self.assertEqual(divmod(5.0, 3.0), (1.0, 2.0))

    def test_enumerate(self):
        evens = [x for x in range(1, 11) if x % 2 == 0]
        self.assertEqual(list(enumerate(evens, start=1)), [(1, 2), (2, 4), (3, 6), (4, 8), (5, 10)])

    def test_exec(self):
        self.assertEqual(eval('5 + 15'), 20)

    def test_float(self):
        self.assertEqual(float(5), 5.0)

    def test_format(self):
        self.assertEqual('Hello World', '{0} {1}'.format('Hello', 'World'))

    def test_hex(self):
        self.assertEqual(hex(65535), '0xffff')

    def test_int(self):
        self.assertEqual(int(6.65), 6)

    def test_len(self):
        self.assertEqual(5, len([1, 2, 3, 4, 5]))

    def test_list(self):
        self.assertEqual(list(range(10)), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

    def test_max(self):
        self.assertEqual(100, max([1, 20, 100, 50, 75, 90]))

    def test_min(self):
        self.assertEqual(3, min(10, 20, 30, 3, 40, 50, 60))

    def test_next(self):
        x = iter([y for y in range(1, 10)])
        self.assertEqual(1, next(x))

    def test_oct(self):
        self.assertEqual('0o764', oct(500))

    def test_round(self):
        self.assertEqual(round(5.3527822, 3), 5.353)

    def test_sorted(self):
        items = [9, 5, 3, 2, 1, 0, .2329, -929, 832, 25, 8, 4, 8]
        self.assertEqual(sorted(items), [-929, 0, 0.2329, 1, 2, 3, 4, 5, 8, 8, 9, 25, 832])

    def test_sum(self):
        nums = [5, 10, 15, 20]
        self.assertEqual(sum(nums), 50)

    def test_sum_true(self):
        self.assertTrue(sum([1, 2, 3]) < 10)

13.10. Text based calculator

17.4s
Python
#########################################
# Text based calculator coding project:
# Due: 05/21/2019 at 10:30 am
#
# Write a simple text based calculator
# that prompts the user for two input,
# and prints out the correct calculations.
#
# The operations to model are:
# addition
# subtraction
# multiplication
# division
# modulus
# square root
# exponential
# basic trigonometry: sin(), cos(), tan()
# shows results both in radians and degrees
# logarithm
#
# By Doug Purcell
# http://www.purcellconsult.com
#
#########################################

from math import sin, cos, tan
from math import radians
from math import log
from math import sqrt

'''
addition operation
'''

a1 = float(input('Addition. Enter first number '))
a2 = float(input('Enter second number '))
a3 = a1 + a2
print(a1, '+', a2, '=', a3)

'''
subtraction operation
'''
a1 = float(input('Subtraction: Enter first number '))
a2 = float(input('Enter second number '))
a3 = a1 - a2
print(a1, '-', a2, '=', a3)

'''
multiplication operation
'''

a1 = float(input('Multiplication: Enter first number '))
a2 = float(input('Enter second number '))
a3 = a1 * a2
print(a1, 'x', a2, '=', a3)

'''
division operation
'''

a1 = float(input('Division: Enter first number '))
a2 = float(input('Enter second number '))
a3 = a1 / a2
print(a1, '/', a2, '=', a3)

'''
modulus operation
'''

a1 = float(input('Modulus: Enter first number '))
a2 = float(input('Enter second number '))
a3 = a1 % a2
print(a1, '%', a2, '=', a3)

'''
square root operation
'''

a1 = float(input('Square root: Enter number to take square root of '))
print('√', a1, '=', sqrt(a1))

'''
Exponentiation
'''

b = float(input("Exponentiation. Enter a number for the 'base' "))
n = int(input('Enter the power '))
result = b ** n
print(b, '^', n, '=', result)

'''
basic trigonometry: sin(), cos(), trig:
in both radians and degrees
'''


a = float(input('Enter number to compute, sin, cos, and tan of '))

# calculate degrees

sine_degs = sin(radians(a))
cosine_degs= cos(radians(a))
tangent_degs = tan(radians(a))

# calculate radians
sine_rads = sin(a)
cosine_rads = cos(a)
tangent_rads = tan(a)

print(sine_degs, '° sine')
print(sine_rads, 'r sine')

print(cosine_degs, '° cosine')
print(cosine_rads, 'r cosine')

print(tangent_degs, '° tangent')
print(tangent_rads, 'r tangent')

'''
Implement the logarithm. In mathematics the
logarithm is the inverse function of
exponentiation.
'''

x = float(input('Logarithm. Enter the value of x '))
base = float(input('Enter the base '))
logarithm = log(x, base)
print('log base', base, 'of', x, '=', logarithm)

13.11. Stat-tastic

sample_dataset.txt
0.7s
Python
##################################
# Stat-tastic!
# ------------
#
# This exercise helps you practice functions
# and rediscover statistics by coding common
# statistical formulas in python.
# Note, can't use the built in statistics module: https://docs.python.org/3/library/statistics.html
# You can't use the max, min, or sorted functions from the python library: https://docs.python.org/3/library/functions.html
#
# Stats formulas: https://www.statisticssolutions.com/common-statistical-formulas
#
# Functions to code:
# ------------------
#
# Total: The total elements in the file
# Summation: The sum of all of the elements in a file
# Sample Mean: The average
# Sample Standard Deviation: Measures the spread of a data distribution
# Sample Variance: How far a set of numbers are spread out from the average value
# min: The smallest number in the file
# max: The largest number in the file
#
# By Doug Purcell
# http://www.purcellconsult.com
#
#####################################

from math import sqrt


# DATA is a constant
DATA = 
sample_dataset.txt
def total(): """ represents the total number n of observations in the sample. """ i = 0 with open(DATA) as file: for line in file: i += 1 return i def summation(): """ sums all of the numbers in a dataset. """ sum = 0 with open(DATA) as file: for line in file: sum += int(line) return sum def sample_mean(): """ calculates the 'average' """ n = total() sum = 0 with open(DATA) as file: for x in file: sum += int(x) return sum / n def sample_variance(): """ a measure of the spread(variability) of the scores in the sample on a given variable. s = sqrt [ Σ ( xi – x_bar )2 / ( n – 1 ) ] """ n = total() with open(DATA) as file: for x in file: sum = (int(x) - n)**2 return sum / (n - 1) def sample_standard_dev(): """ The average of the squared differences from the mean. """ std_dev = sample_variance() return sqrt(std_dev) def median(): """ calculates the median for a dataset. """ items = [] with open(DATA) as file: for x in file: items.append(int(x)) ordered = sorted(items) size = total() if size % 2 == 0: middle = int(size / 2) return ordered[middle] else: middle = size // 2 return ordered[middle] def min(): """ one way to compute the minimum number in the dataset. """ items = [] with open(DATA) as file: for x in file: items.append(int(x)) i = 0 min = items[0] while i < len(items): if items[i] < min: min = items[i] i += 1 return min def max(): """ one way to compute the max number in the dataset. """ items = [] with open(DATA) as file: for x in file: items.append(int(x)) max = items[0] i = 0 while i < len(items): if items[i] > max: max = items[i] i += 1 return max print(total()) print(summation()) print(sample_mean()) print(sample_variance()) print(sample_standard_dev()) print(median()) print(min()) print(max())