Open In Colab

Lesson 3 Basics

Pragmatic AI Labs

alt text

This notebook was produced by Pragmatic AI Labs. You can continue learning about these topics by:

3.1 Write procedural code

### Procedural Statements Procedural statements are literally statements that can be issued one line at a time. Below are types of procedural statements. These statements can be run in:

  • Jupyter Notebook
  • IPython shell
  • Python interpreter
  • Python scripts
three_type_of_energy = ["protein", "carbohydrates", "fat"]

Multiple procedural statements

protein, carbohydrate, fat = three_type_of_energy
print(f"{carbohydrate} sure taste good")
print(f"{fat} isn't bad for you anymore?")

carbohydrates sure taste good
fat isn't bad for you anymore?

Adding Numbers

protein = 4
fat = 9
carbohydrate = 4
carbohydrate + protein
8

Adding Phrases

"a carbohydrate " + "has " + str(carbohydrate) + " calories" 
'a carbohydrate has 4 calories'

Complex statements

More complex statements can be created that use data structures like the belts variable, which is a list.

for energy_type in three_type_of_energy:
  print(energy_type)
protein
carbohydrates
fat

3.2 Use simple expressions and variables

assert

assert carbohydrate == 9
  

    ---------------------------------------------------------------------------

    AssertionError                            Traceback (most recent call last)

    <ipython-input-65-448b002ebeaf> in <module>()
    ----> 1 assert carbohydrate == 9
          2 


    AssertionError: 


assert carbohydrate == 4

pass

class Calorie: pass
kcal = Calorie()

kcal.value = "9"

del

class Calorie: pass
kcal = Calorie()
%who_ls
['Calorie',
 'breakfast',
 'calories',
 'carb',
 'carbohydrate',
 'carbs',
 'egg_set',
 'energy',
 'energy_type',
 'fat',
 'food',
 'ingredients',
 'kcal',
 'omelette',
 'protein',
 'snacks',
 'this',
 'three_type_of_energy',
 'too_much_food',
 'variable']
kcal.value = 9
del kcal
%who_ls
['Calorie',
 'breakfast',
 'calories',
 'carb',
 'carbohydrate',
 'carbs',
 'egg_set',
 'energy',
 'energy_type',
 'fat',
 'food',
 'ingredients',
 'omelette',
 'protein',
 'snacks',
 'this',
 'three_type_of_energy',
 'too_much_food',
 'variable']

return

def food():
  return "whey"

print(f"Make {food()} while the sun shines")
Make whey while the sun shines

yield

def too_much_food():
  meal = ["orange", "apple", "turkey", "ham"]
  for snack in meal:
    yield snack
    
snacks = too_much_food()
print(next(snacks))
print(next(snacks))
orange
apple

next(snacks)
'turkey'
next(snacks)
'ham'
next(snacks)

    ---------------------------------------------------------------------------

    StopIteration                             Traceback (most recent call last)

    <ipython-input-78-4cb0aa5aecce> in <module>()
    ----> 1 next(snacks)
    

    StopIteration: 


break

carbohydrate = 4
calories = 0
while True:
  calories += carbohydrate
  print(f"Eating more carbohydrates {calories}")
  if calories > 8:
    print("This is all I can eat")
    break
Eating more carbohydrates 4
Eating more carbohydrates 8
Eating more carbohydrates 12
This is all I can eat

continue

three_type_of_energy = ["protein", "sugar", "fat"]
for energy in three_type_of_energy:
  if energy == "sugar":
    print(f"skipping {energy} for my health")
    continue
  print(f"eating {energy}")
eating protein
skipping sugar for my health
eating fat

import

import this

3.3 Work with the built-in types

dict

omelette = {"egg": 3, "ham": "yes"}
type(omelette)
dict

list

ingredients = ["egg", "ham", "bacon"]
type(ingredients)
list

set

egg_set = set(["egg", "egg"])
type(egg_set)
set
egg_set
{'egg'}

tuple

breakfast = ("egg","soup")
breakfast[0] = "turkey"

    ---------------------------------------------------------------------------

    TypeError                                 Traceback (most recent call last)

    <ipython-input-96-5737173ae030> in <module>()
          1 breakfast = ("egg","soup")
    ----> 2 breakfast[0] = "turkey"
    

    TypeError: 'tuple' object does not support item assignment


breakfast[1]
'soup'

3.4 Printing

Printing

print("omelets are tasty")

omelets are tasty

variable = "ham"
print(f"I like {variable}")
I like ham

Create Variable and Use Variable

variable = "omelets";print(variable)
omelets

Use print as a function

print("kombucha", "manuka honey", sep="+")
kombucha+manuka honey

3.5 Perform basic math operations

Numbers and Arithmetic Operations

Python is also a built-in calculator. Without installing any additional libraries it can do many simple and complex arithmetic operations.

Adding and Subtracting Numbers

steps = (1+1)-1
print(f"Two Steps Forward:  One Step Back = {steps}")
Two Steps Forward:  One Step Back = 1

Multiplication with Decimals

Can use float type to solve decimal problems

body_fat_percentage = 0.10
weight = 200
fat_total = body_fat_percentage * weight
print(f"I weight 200lbs, and {fat_total}lbs of that is fat")
I weight 200lbs, and 20.0lbs of that is fat

Can also use Decimal Library to set precision and deal with repeating decimal

from decimal import (Decimal, getcontext)

getcontext().prec = 2
Decimal(1)/Decimal(3)


Decimal('0.33')

Using Exponents

Using the Python math library it is straightforward to call 2 to the 3rd power

import math
math.pow(2,3)
8.0

Can also use built in exponent operator to accomplish same thing

2**3
8

multiply

2*3
6

this is regular multiplication

2*3
6

Converting Between different numerical types

There are many numerical forms to be aware of in Python. A couple of the most common are:

  • Integers
  • Floats
number = 100
num_type = type(number).__name__
print(f"{number} is type [{num_type}]")
100 is type [int]

number = float(100)
num_type = type(number).__name__
print(f"{number} is type [{num_type}]")
100.0 is type [float]

class Foo:pass
f = Foo()
type(f)
__main__.Foo

Numbers can also be rounded

Python Built in round

too_many_decimals = 1.912345897
round(too_many_decimals, 3)
#get more info
#round?
1.912

Numpy round

import numpy as np
np.round(too_many_decimals, 3)
1.912

Pandas round

import pandas as pd
df = pd.DataFrame([too_many_decimals], columns=["A"], index=["first"])
df.round(2)

A
first 1.91

Simple benchmark of all three (Python, numpy and Pandas round): using %timeit

*Depending on what is getting rounded (i.e. a very large DataFrame, performance may very, so knowing how to benchmark performance is important with round) *

print("built in Python Round")
%timeit round(too_many_decimals, 2)

print("numpy round")
%timeit np.round(too_many_decimals, 2)

print("Pandas DataFrame round")
%timeit df.round(2)
built in Python Round
The slowest run took 21.00 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 486 ns per loop
numpy round
The slowest run took 9.26 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 7.62 µs per loop
Pandas DataFrame round
1000 loops, best of 3: 951 µs per loop

3.6 Use classes and objects with dot notation

Interacting with Special Class Methods and Other Class Techniques

Class special methods have the signature __method__:

Examples include

__len__
__call__
__equal__

l = [1,2]
len(l)
#class Foo:pass
#f = Foo()
#len(f)
2
class JonJones:
  """Jon Jones class with customized length"""
  
  def __len__(self):
    return 84

jon_jones = JonJones()
len(jon_jones)
84
class foo():pass
f = foo()
f.red = "red"
len(f)

    ---------------------------------------------------------------------------

    TypeError                                 Traceback (most recent call last)

    <ipython-input-123-f0f0529fb27b> in <module>()
          2 f = foo()
          3 f.red = "red"
    ----> 4 len(f)
    

    TypeError: object of type 'foo' has no len()


@property decorator is a shortcut for creating a read only property

class JonJones:
  """Jon Jones class with read only property"""
  
  @property
  def reach(self):
    return 84

jon_jones = JonJones()
jon_jones.reach
#jon_jones.reach = 85 #cannot set
jon_jones.length = 85
jon_jones.length
85
jon_jones.reach
jon_jones.reach = 85

    ---------------------------------------------------------------------------

    AttributeError                            Traceback (most recent call last)

    <ipython-input-127-c873d37e7994> in <module>()
          1 jon_jones.reach
    ----> 2 jon_jones.reach = 85
    

    AttributeError: can't set attribute


@staticmethod bolts a function onto a class

class JonJones:
  """Jon Jones Class with 'bolt-on' reach method
  self isn't needed
  """
  
  @staticmethod
  def reach():
    return 84

jon_jones =JonJones()
jon_jones.reach()
84

Immutability concepts with Objects

class Foo:
  
  @property
  def unbreakable(self):
    return "David"


foo = Foo()
foo.unbreakable 
'David'
foo.not_unbreakable = "Elijah"

@property acts like an read only attribute, but it isn’t

foo.__dict__
{'not_unbreakable': 'Elijah'}

You can change an attribute on the object, but not the read only property

foo.not_unbreakable = "Mr. Glass"
foo.unbreakable = "Bruce Willis"

    ---------------------------------------------------------------------------

    AttributeError                            Traceback (most recent call last)

    <ipython-input-137-4bc1ea5ae699> in <module>()
    ----> 1 foo.unbreakable = "Bruce Willis"
    

    AttributeError: can't set attribute


Notes