Week 1: Course Overview and Python Basics

Video 1.1: Course Logistics and Overview

The course website contains all important information about the course:

- Syallabus 
- Course Calendar 
- Assignments 
- Remote Learning: Panopto Videos 
- Remote Learning: Zoom live Videos 
- Piazza
- Gitlab (Repositories) 

Course Website: http://people.cs.uchicago.edu/~lamonts/classes/2019_2020/fall/mpcs51042/index.html

Video 1.2: Python Introduction

Video Outline

  1. Why learn Python?
  2. How to run a Python program?

Section #1.2.1: Why Learn Python?

In my opinion, here are the reasons to learn Python:

  1. Easy to learn:

    Python's syntax is relatively simple with very few rules and special cases. The syntax allows for rapid prototyping, which allows for you to focus on what you want to do with the code and quickly experiment and implement ideas. You typically spend less time in Pythong worrying about language intricacies.

  1. It is an open source, general-purpose and multiparadigm programming language:

    Allows for implementing applications in many different domains (e.g., data science, artificial intelligence, web development, systems level scripting, etc). With more than 20 years of development, it is available on many different platforms (Linux, Windows, MacOS, etc.) and works as intended on these platforms. It also allows programmers to develop code using a combination of different programming paradigms such as procedural, object-oriented, and functional programming.

  1. Continues to be a popular language:

    alt text -- https://stackoverflow.blog/2017/09/06/incredible-growth-python/

alt text -- https://stackoverflow.blog/2017/09/06/incredible-growth-python/

  1. You want a job in Data Science and Artificial Intelligence (especially Machine learning):

    Python is the preferred programming languages in many regards in the data ccience and machine learning fields. With its vast number of packages in these areas, other languages cannot match the level of sophicastion of these packages bring to the language.

Note: There are areas where using Python would probably not be appropriate. Throughout this course, I'll make sure to talk about the pitfalls of the language as well.

Section 1.2.2 : Running Python Programs

When learning new languages, the traditional first program is the one that prints the text "hello world" to the terminal. Here's the implemenetation in Python.

In [5]:
# This will print "Hello World" to the console
print("Hello World")
Hello World

Notes:

  • print is a built-in function. It takes a value and prints it to the terminal.
  • Comments (i.e., code documentation) is done via #.

Running this program

In Python, there are two ways of running code:

  1. Using an interactive prompt via the Python interpreter (i.e., a program that executes other programs. Using the interpreter in its interactive mode, will execute the instructions (i.e., the statements in your code) one by one. You write a line of code, you hit enter, and the interpreter executes that line of code and shows the result (if any).

    • The interpreter is accessible via the terminal program on your machine.

    • The interpreter is also known as a RELP (read, eval, print, loop)

    • The REPL is great for learning, experimenting, and testing Python code

  • Demo: Using the IPython interpreter to print Hello World
  1. Saving your code in a file and then running that file using the interpreter.
  • Demo: Create a blank file called hello.py, write print("Hello, world!") inside it, and then run::

    ipython hello.py

Note: We will discuss how the interpter works in the coming weeks.

Python Programs

As stated before, the REPL a good tool for experimenting with code interactively. Once your code becomes complex then you will want to save it as a Python program. These programs are saved in a .py file (or a collection of .py files).

Aside: Python Versions

Python2 and Python3 are the two main versions of Python. However, the end of life for Python2 happend at the beginning of 2020; therefore, Python3 is the future of the language and is the one we will use.

Video 1.3: Python Basics

Video Outline

  1. Variables & Types in Python
  2. Numeric Types
  3. Sequence Types

Section #1.3.1: Python Basics

You all have prior programming experience; therefore, I want to quickly go over the syntax for common programming constructs in Python.

We will learn about more advance features of these constructs over the next few weeks. For now, I will just show you the basic syntax for them.

Variables

A variable in Python has the following syntax:

variable_name = expression

Notes:

  • Each variable_name should be in all lowercase letters with words seperated by an underscore.
  • Constant variables should be all uppercase characters with words seperated by an underscore (CONSTANT_NAME).
  • Remember an expression is just a combination of one or more constants, variables, operators, functions, etc.
In [6]:
x = 1234
In [7]:
y = True
In [8]:
z = 4
In [12]:
var = x + z 
var
Out[12]:
1238

Types

Notice how I did not specify the type for the above variables. This is because Python is a dynamically-typed language: it automatically determines and keeps track of varible types without requiring a type declaration. Other languages, like Java and C/C++, are statically-typed and require the programmer to specify the type of every variable. For example, in Java we would need to declare the variable x from above as:

int x = 1234; 

At any point you can determined the infered type for a variable by using the type(variable_name) function.

In [13]:
type(x) 
Out[13]:
int
In [14]:
type(y)
Out[14]:
bool

We will learn more about Python's type system next week.

Core Data Types

As with other programming languages, Python provides built-in core types:

  • Numeric types: int, float, complex
  • Sequence types: str, list, tuple
  • Boolean: bool
  • Set types: set
  • Mapping types: dict

In week #1, we will cover the numeric, sequence, and boolean types. Next week, we will talk about the set and mapping types.

Numeric Types

The following diagram provides examples of numeric values in Python:

alt text -- Learning Python 2013

  • Specialized numeric types (e.g., Fraction Decimal) can be imported from the standard library.

  • Explicit conversion of the numeric types are done using the int(), float() and complex() functions.

In [15]:
x = 235
x
Out[15]:
235
In [16]:
y = float(x) #convert the integer value for x into a float value 
y
Out[16]:
235.0

Numeric Expressions/Operators

The following diagram provides examples of defining numeric expressions using the common numeric operators provided in Python:

alt text -- Learning Python 2013

Note: the evaluation of numeric expressions are done similiarly to the order of precedence in other languages:

Order of Precedence in Python:https://docs.python.org/3/reference/expressions.html#summary

Arithmetic Conversion

Mixed arithmetic is allowed. Python converts operands up to the type of the most complicated operand. Converting up is also done at the expression level.

  • Highest to lowest: complex numbers -> floating point numbers -> integers
In [17]:
34 + 3.2 # Conversion = 34.0 + 3.2 = 37.2
Out[17]:
37.2
In [18]:
(3 + 5) - 4.0 # Conversion = (3.0 + 5.0) - 4.0 = 4.0
Out[18]:
4.0

Boolean type

As with other languages, the values that represent booleans are defined as:

  • Case-sensitive truth value: True
  • Case-snesitive false value: False

Relational Operators

  • Operators that tests or defines some kind of relation between two values.
Syntax Definition
x > y True if left operand is greater than the right
x < y True if left operand is less than the right
x == y True if both operands are equal
x != y True if both operands are not equal
x >= y True if left operand is greater than or equal to the right
x <= y True if left operand is less than or equal to the right
In [19]:
3 <= 12
Out[19]:
True
In [20]:
5 == 7
Out[20]:
False

Logical Operators

  • Operators that perform logical AND, logical OR, and logal NOT
  • These operators short-circuit (i.e., when an expression is stopped being evaluated as soon as its outcome is determined.)
Syntax Definition
x and y True if both the operands are true
x or y True if either of the operands is true
not x True True if operand is false
In [21]:
3 <= 12 and 4 >= 4 
Out[21]:
True
In [22]:
b = False 
not b
Out[22]:
True

None Type

As with many other languages, there is a value in Python that represents the absence of a value. In Python, this is known as the None type and has a single value as None.

We will talk more about the use cases of None as we progress in the course.

In [23]:
x = None 
print(x)
None

Sequence types

Sequences allow you to store multiple values in an organized and effcient way. The sequence types we will examine will be str, list, and tuple.

Strings

  • Strings (i.e., str type in Python) are used to record both textual information and arbitrary collections of bytes.

  • String are immutable sequences: positionally ordered collection of other objects that cannot be modified.

  • String transformation operations/functions always produce new str values.

There are many different ways of defining a str in Python

In [18]:
# Single quote literal
# Allows you to embed double quotes (") inside the string 
str1 = 'spa"m'
print(str1)
type(str1)
spa"m
Out[18]:
str
In [24]:
# Double quote literal
# Allows you to embed double quotes (') inside the string 
str2 = "spa'm"
print(str2)
spa'm
In [25]:
# Triple quote literal (multi-line strings)
# Multi-line strings include the newlines 
str3 = '''Here is a list of names all on different lines 
""Bob"
"Sally" 
"Joe" 
"Karen"'''
print(str3) # Notice the newlines are preserved
Here is a list of names all on different lines 
""Bob"
"Sally" 
"Joe" 
"Karen"
In [26]:
# Double quote version (multi-line strings) 
# Allows for escaping single quotes ''
str3 = """Here is a list of names all on different lines 
'Bob'
'Sally' 
'Joe'
'Karen'"""
print(str3)
Here is a list of names all on different lines 
'Bob'
'Sally' 
'Joe'
'Karen'
In [27]:
# As with other languages, you can have escape characters in strings 
# \t - tab character 
# \n - newline character
# Many others: https://www.w3schools.com/python/gloss_python_escape_characters.asp
str5 = "Bob\tSally\nJoe"
print(str5)
str6 = 'Bob\tSally\nJoe'
Bob	Sally
Joe
In [23]:
#Below is an example of "raw strings", which include escape characters 
# a raw string always begins with a "r" before the string syntax 
str7 = r'C:\new\test.py' 
non_raw_str7 = 'C:\new\test.py'

#Notice the strings actually contain the \n and \t in the ouput versus 
# the non-raw versions 
print(str7) 
print("----")
print(non_raw_str7)
C:\new\test.py
----
C:
ew	est.py

String Formatting

Another way to define strings is to format them. Formattting allows you to incorporate values from other types to produce a new string.

The following are a few ways to produce a formatted string.

In [28]:
# By relative position '{}' using the "format" method. 
# Auto-conversion for non-strings. 
f_str = 'Address = {} {} {}'.format(4543, 'Elaine', 'Street')
print(f_str)
Address = 4543 Elaine Street
In [29]:
# By absolute position '{index}', where index is an integer 
f_str2 = 'Hello {2}, {0} and Bye {1}'.format('Bob','Sally','Joe')
print(f_str2)
Hello Joe, Bob and Bye Sally
In [30]:
# By keyword. Specify keyword first followed by the value.
f_str3 = 'Address = {num} {name} {suffix}'.format(num = 4543, name = 'Elaine', suffix = 'Street')
print(f_str3)
Address = 4543 Elaine Street
In [33]:
# New in Python 3.6+: formatted string literals. 
# IMPORTANT - Note the 'f'. This 'f' is required!

#Define a few variables 
num = 4543 
name = 'Elaine'
suffix = 'Street' 

# Directly place your expressions inside the curly braces
f_str4 = f'Address = {num} {name} {suffix}'
print(f_str4)
Address = 4543 Elaine Street

The string formatting method includes additional options for formatting:

  • Precision: number of decimals for float objects
  • Hex, binary, or octal representation for ints
  • Justification options and whitespace padding

Documentation:

Lists

One of the most useful sequence types are lists (list) and they are:

  • A great data structure if you need to hold a collection of positionally-ordered and arbitrarily-typed values.

  • Mutable (i.e., they can be modified in-place)

  • Dynamically Resizable (i.e., they can be shorten or extended as needed)

List Creation

There are many different ways to define a list in the Python. The following code sections provide a few ways.

In [34]:
# Empty List 
lst = [] 
lst
Out[34]:
[]
In [35]:
# Defining a list with specified items 
# Remember a list can contain values of different types. 
lst = [123, 'abc', 1.23]
lst
Out[35]:
[123, 'abc', 1.23]
In [36]:
# Nested lists (lists within lists) 
lst = ['Bob', 40.0, ['dev', 'mgr']]
lst
Out[36]:
['Bob', 40.0, ['dev', 'mgr']]

Tuples

A tuple is an immutable sequence of arbitrary objects that are also:

  • Fixed-length
  • Heterogeneous
  • Arbitrarily nestable

Tuple Creation

There are many different ways to define a tuple in the Python. The following code sections provide a few ways.

In [37]:
# Empty Tuple
tup = () 
tup 
Out[37]:
()
In [38]:
# A one-item tuple (not an expression)
tup = (0,) 
tup 
# Asside: Why couldn't we just use say (0)? 
Out[38]:
(0,)
In [39]:
# A four-item tuple  
tup = (0, 'Ni', 1.2, 3)

# Another four-item tuple (same as prior line) without the need for the parenthesis 
tup2 = 0, 'Ni', 1.2, 3 

print(tup)
print(tup2)
(0, 'Ni', 1.2, 3)
(0, 'Ni', 1.2, 3)

Aside: It seems that lists and tuples are the same. They both hold a collection of values but they have slightly different syntax. When should you use one over the other? We will talk about this next week.

Sequence Operations

All sequence types (e.g., str, list, tuple) support a series of useful operations:

  • Length (len):

    - Determines the size of a sequence value. 
    - The result is an integer value. 
  • Concatenation(+):

    • Combine sequence values together
    • The result is a new sequence value
  • Repetition(*):

    • Repeat a sequence value a certain number times
    • The result is a new sequence value
  • Containment(in):

    • Determines whether a sequence value is inside another one
    • The result is a boolean value.
In [40]:
# Length

# Strings
print(len('spam'))
print('---')

# Lists 
lst = ['a', 'b', 1]
print(len(lst))
print('---')

# Tuples 
tup = (1,2,True,False,"Hi")
print(len(tup))
4
---
3
---
5
In [41]:
# Concatenation 

# Strings 
str1 = 'hello ' + 'world ' + 'helloworld'
print(str1)
print('---')

# Lists 
lst = ['a']
new_lst =  lst + [4, 5, 6]
print(new_lst)
print('---')

# Tuples 
print((1, 2) + (3, 4))
hello world helloworld
---
['a', 4, 5, 6]
---
(1, 2, 3, 4)
In [42]:
# Repetition

# Strings 
t = 'hi' * 4 
print(t)
print('---')

# Lists 
new_lst = lst * 2 
print(new_lst)
print('---')

# Tuples 
tup = (1,2)
new_tup = tup * 4
print(new_tup)
hihihihi
---
['a', 'a']
---
(1, 2, 1, 2, 1, 2, 1, 2)
In [43]:
# Containment

# Strings
print('M' in 'MPCS')
print('T' in 'MPCS')
print('CS' in 'CS') # Substring containment example 
print("---")

# Lists 
print(4 in lst)        # 4 is not in the list 
print ('a' in lst)     # 'a' is iniside the list 
print('---')

# Tuples 
tup = (1,2,True,False,"Hi")
print("Bob" in tup)
print("2" in tup)
print(1 in tup)
True
False
True
---
False
True
---
False
False
True

Sequence Indexing

Sequence types provides the indexing notation (S[i]) to fetch a single item from the a sequence value.

In [47]:
# Sequence Indexing is zero-based (i.e., the first item in the sequence is at index 0)

# Strings
str1 = 'spam'
print(str1[0])
print(str1[2])
print('---')

# Lists 
lst = ['a', 'b', 1]
print(lst[0])
print(lst[2])

# Since Lists are mutable we can use indexing to update the elements. 
# Remember you cannot due the following with strings or tuples because they are immutable! 
# If you try to update immutable sequences then an error will be raised. 
print(lst)  # Before update ['a','b', '1']
lst[0] = 3 
lst[1] = 5 
print(lst)  # After updating [3,5,1]
print('---')

# Tuples 
tup = (1,2,True,False,"Hi")
print(tup[3])
print(tup[2])
s
a
---
a
1
['a', 'b', 1]
[3, 5, 1]
---
False
True
In [48]:
# Python allows for "backwards indexing". Placing a "-"
# before the integer index will force indexing to begin from the end 
# of a sequence. 

# Strings 
str1 = 'spam'
print(str1[-1]) # 'm' is the last character (-1) 
print(str1[-2]) # 'a' is the second to the last character (-2)
print('---')

# Lists 
lst = ['Bob', ['a','b','c'], 5, 6]
print(lst[-1])  # 6 is the last element in the list (-1) 
print(lst[-3])  # ['a','b','c'] is the third to the last element (-3)

# Since Lists are mutable we can use indexing to update the elements. 
# Remember you cannot due the following with strings or tuples because they are immutable! 
# If you try to update immutable sequences then an error will be raised. 
lst[-1] = "Hello"
lst[-3] = "World"
print(lst)
print('---')


# Tuples 
tup = (1,2,True,False,"Hi")
print(tup[-1]) # "Hi" is the last element in the list (-1) 
print(tup[-2]) # False is the second to the last element (-2)
m
a
---
6
['a', 'b', 'c']
['Bob', 'World', 5, 'Hello']
---
Hi
False

Sequence Slicing

Slicing is a from of sequence indexing, where it returns an entire section (i.e. a copy) of a sequence.

  • Syntax(S[i:j]):
    • S is a sequence value
    • the lower bound (i) is inclusive (defaults to zero if not specified)
    • the upper bound (j) is nonclusive (defaults to len(S) if not specified)

Note: There is an extended version of sequence slicing. We will talk about that next week.

In [49]:
S = 'MPCS51042'
lst = ['Bob', 'Sally', 'Tina']
tup = (1,2,3,4,5)
In [51]:
# Fetches items at offsets 1 up to but not including 3
print(S[1:3])
print('---')
print(lst[1:3])
print('---')
print(tup[1:3])
PC
---
['Sally', 'Tina']
---
(2, 3)
In [52]:
# Fetches items at offset 1 through the end (the sequence length) 
print(S[1:])
print('---')
print(lst[1:])
print('---')
print(tup[1:3])
PCS51042
---
['Sally', 'Tina']
---
(2, 3)
In [53]:
# Fetches items at offset 0 up to but not including 3
print(S[:3])
print('---')
print(lst[:3])
print('---')
print(tup[:3])
MPC
---
['Bob', 'Sally', 'Tina']
---
(1, 2, 3)
In [54]:
# Fetches items at offset 0 up to but not including the last item 
print(S[:-1])
print('---')
print(lst[:-1])
print('---')
print(tup[:-1])
MPCS5104
---
['Bob', 'Sally']
---
(1, 2, 3, 4)
In [55]:
# Creates a copy of S (i.e, [0, len(S)])
print(S[:])
print('---')
print(lst[:])
print('---')
print(tup[:])
MPCS51042
---
['Bob', 'Sally', 'Tina']
---
(1, 2, 3, 4, 5)

String methods

Python provides collection of methods (i.e., functions that act on values) that create new strings based on the behavior of the method.

Syntax: str_value.method_name(arg1,arg2,...)

  • str_value - a string value or variable
  • .method_name - the notation to call a specific string method_name. For example,

    • upper : capitalizes all the letters of the string.
    • lower : lower cases all the letters of the string.
    • split : returns a list of words in a string where default separator is any whitespace.
    • find : returns the lowest index of a particular substring in a string. If the substring is not found, -1 is returned.
    • replace : Replace all occurences of a substring with a new substring.
    • strip : returns a copy of the string with the leading and trailing characters removed. Default character to be removed is whitespace.

    • More string methods : https://docs.python.org/3/library/stdtypes.html#string-methods

  • (arg1,arg2,...) - the arguments for that method.
In [56]:
spam = "spammy"
# Replace all mm with xx in S 
new_spam = spam.replace('mm', 'xx')
print(new_spam)
print(spam) # Remember old string is not modified. Strings are immutable 
spaxxy
spammy
In [47]:
spam = '----SPAM----SPAM----'
#Search for the index of the first occurence of "SPAM" 
where = spam.find('SPAM') 
print(where)
4
In [59]:
words = 'abc edf g'
# Creates a list of strings. The words are deliminted by default via a whitespace
lst = words.split() 
print(lst)
print('---')
words = "abc,efg,g"
lst = words.split(",") # Can specify the deliminter 
print(lst)
['abc', 'edf', 'g']
---
['abc', 'efg', 'g']
In [60]:
# If possible, you can convert any value into a str value by using the "str()" conversion function. 
str1 = str(1.234)
str2 = str("True")
str3 = str([1,2,3])
print(str1)
print(str2)
print(str3)
print(type(str1))
print(type(str2))
print(type(str3))
1.234
True
[1, 2, 3]
<class 'str'>
<class 'str'>
<class 'str'>

Mutable Sequences Methods/Operators

Below are some common methods associated with mutable sequences. All of these methods change the sequence in-place.

alt text -- https://docs.python.org/3/library/stdtypes. html#mutable-sequence-types

In [50]:
lst = [1,2,3,4]
lst.append("hi")
lst.append(True)
print(lst)
[1, 2, 3, 4, 'hi', True]
In [61]:
lst.pop()  # Removes last element 
print(lst)
['abc', 'efg']

Aside: Range Sequence Type

There is one more important immutable sequence type to discuss range. The range type is an immutable sequence of numbers and is commonly used for looping a specific number of times in for loops.

Syntax: range(stop) or range(start,stop) or range(start,stop,step):

  • start: The value of the start parameter (or 0 if the parameter was not supplied) inclusive
  • stop : The value of the stop parameter exclusive
  • step : The value of the step parameter (or 1 if the parameter was not supplied)
  • The range type implementes all common sequence operatrions except for concatenation and repetition
  • The main advantage of the range type is that it always take the same (small) amount of memory, no matter the size of the range it represents.
In [62]:
r = range(6) # Contains an ordered collection of the values: 0,1,2,3,4,5
print(r[0])
print(r[len(r) - 1]) # Last value in the range
print('----')

r = range(1,4) # Contains an ordered collection of the values: 1,2,3
print(r[0])
print(r[-1])
print('----')

# Printing the range value does not show you the contents because the values are generated when needed
print(r) 
# You can convert it into a list to see the values 
print(list(r))
0
5
----
1
3
----
range(1, 4)
[1, 2, 3]

Video 1.4: Control-Flow and Modules

Video Outline

  1. If-statements
  2. Loop statements: for, while loops
  3. Function basics
  4. Module Basics

Control-Flow

Python uses the usual flow control statements known from other languages with some caveats

Indentation Rules

  • Unlike many other languages (C,C++,Java), Python does not use braces {} to designate code blocks.

  • Python uses indentation to signify code block boundaries.

  • Statements indented to the same distance belong to the same block of code.

  • Blocks end:

    • When the end of file is detected.
    • When a lesser-indented line is detected.
  • Examples of indented statements: for, while, if

  • Deeply nested blocks are further indented to the right

If Statments

The if statement allows for selecting from alternative actions based on conditional expression results.

Syntax:

if condition: 
    statement1
    statement2
elif condition2:   #Else if clause, if the first condition fails then we try the next else if clause
    statement3 
else: 
    statement4

Notes:

  • There needs to be a colon (:) after the end of the condition (or the else keyword) to signal the beginning of the clause block
  • Both the elif and else statements are optional.
  • Parentheses around the conditional expressions are optional.
  • Lines below the if, elif, or else must be indented over 4 spaces.
In [64]:
bmi = 31

#Determine the BMI category
if bmi < 18.5:
    print("Underweight")
elif bmi >= 18.5 and bmi < 24.9:
    print("Normal weight")
elif bmi >= 24.9 and bmi < 29.9:
    print("Overweight")
else: 
    print("Obese")
Obese

For statements

The for statement is a looping statement that steps through items in any sequence or iterable object (more on this later...)

Syntax:

For every iteration of the below for loop, it assigns the items in the sequence (or iterable object) to item (one by one) and then executes the loop body.

for item in sequence: 
    statement1          # Statement1 is executed every iteration 
    if cond_exp:          
       break            # Immediately goes to statement4
    if cond_exp:           
       continue         # Immediately goes to the next iteration 
    statements2         # Statement2 is executed if the continue or break was not encountered.
else:
   statement3           # Statement3 is executed if loop exits without a break 

statements4             # Statement4 is executed no matter how the loop exts
In [65]:
bmis = [12,23.45,17.56,32.34,5.6]

for bmi in bmis: 
    category = ''
    #Determine the BMI category
    if bmi < 18.5:  
        category = "Underweight"
    elif bmi >= 18.5 and bmi < 24.9:
        category = "Normal weight"
    elif bmi >= 24.9 and bmi < 29.9:
        category = "Overweight"
    else: 
        category = "Obese"
    
    output = f'BMI = {bmi}, Category = {category}'
    print(output)
else: 
    print("Processed all bmis successfully")
BMI = 12, Category = Underweight
BMI = 23.45, Category = Normal weight
BMI = 17.56, Category = Underweight
BMI = 32.34, Category = Obese
BMI = 5.6, Category = Underweight
Processed all bmis successfully
In [66]:
# Useful For loop Idioms 

# Iterating over a range of numbers using range 
for num in range(10):
    print(num)
0
1
2
3
4
5
6
7
8
9
In [68]:
# Iterating over first 20 even numbers 
for even_num in range(2,21,2): # 21 because the stop is exclusive 
    print(even_num)
2
4
6
8
10
12
14
16
18
20
In [69]:
# Iterating over a collection of items and their indicies 
# Call the "enumerate" function on the sequence 
bmis = [12,23.45,17.56,32.34,5.6]

for index,element in enumerate(bmis):
    print(f'Index = {index}, BMI = {element}')
Index = 0, BMI = 12
Index = 1, BMI = 23.45
Index = 2, BMI = 17.56
Index = 3, BMI = 32.34
Index = 4, BMI = 5.6

While Statement

A while loop repeatedly executes a block of statements as long as its condition expression evaluates to a True value.

while condition: 
    statement1          # Statement1 is executed every iteration 
    if cond_exp:          
       break            # Immediately goes to statement4
    if cond_exp:           
       continue         # Immediately goes to the next iteration 
    statements2         # Statement2 is executed if the continue or break was not encountered.
else:
   statement3           # Statement3 is executed if loop exits without a break 

statements4             # Statement4 is executed no matter how the loop exts
In [70]:
bmis = [23.45,18.67,32.34,5.6]
index = 0
# Keep looping while all values are not underweight
while True: 
    bmi = bmis[index]
    index = index + 1
    if bmi < 18.5:
        break 
    elif bmi >= 24.9:
        continue 
        
    #Only printing normal weight bmis 
    print(f'BMI = {bmi}, Category = Normal Weight')
    
BMI = 23.45, Category = Normal Weight
BMI = 18.67, Category = Normal Weight

Function Basics

A function is a set of statements that can be called more than once.

Benefits of functions:

  • Encapsulation: package logic for use in multiple places
  • Allows programmer to avoid copy/paste to repeat same task, which helps maximize code reuse and minimize redundancy
  • Procedural decomposition: split our program into subtasks (i.e., functions) with separate roles.
  • Make life easier for debugging, testing, doing maintenance on code

Function Syntax

def name(arg1, arg2, ..., argN): 
     ''' 
         Description of function task 

         Inputs: 
             arg1(type): description of arg1 
             arg2(type): description of arg2
             ... 
             argN(type): description of argN

         Outputs:
             Description of what this function returns 

    '''
    statement1
    statement2
    ...
    return value

The following are the steps to define a function:

  1. The def defines a new function called name.
  2. Define zero or more parameters separated by commas in parentheses
  3. A colon to indicate the beginning of the function body.
  4. Every function must define a docstring: A docstring is a string literal that provides a description of the function, input arguments and output result.
  5. Statements inside function are indented over and don’t run until the function is called
  6. return can appear anywhere in body of function
    • Can also be omitted. A function that does not return a value will return None by default.
In [71]:
def bmi_category(bmi): 
    '''
    Calculates the bmi category given a bmi value 
    
    Inputs: 
       bmi(float): the bmi value to use 
    
    Output:
       Returns the bmi category for the bmi value. 
    
    '''
    category = ""
    if bmi < 18.5:  
        category = "Underweight"
    elif bmi >= 18.5 and bmi < 24.9:
        category = "Normal weight"
    elif bmi >= 24.9 and bmi < 29.9:
        category = "Overweight"
    else: 
        category = "Obese"
        
    return category 

# Call the function by specifying its name followed by any necessary arguments to the function 
print(bmi_category(17.34))
print(bmi_category(24.53))
Underweight
Normal weight

Pass statement

The pass statement useful when you are not ready to write the implementation for a code block. The statement allows the interpreter to perform no operation and to continue processing the next statement.

In [60]:
def bmi_category(bmi): 
    '''
    Calculates the bmi category given a bmi value 
    
    Inputs: 
       bmi(float): the bmi value to use 
    
    Output:
       Returns the bmi category for the bmi value. 
    
    '''
    pass # IMPLEMENT ME

print("----begin processing bmi values---")
print(bmi_category(17.34)) # No error, prints None because we do not have a return statement so None is returned 
print(bmi_category(24.53)) # No error, prints None because we do not have a return statement so None is returned 
print("Done.")
----begin processing bmi values---
None
None
Done.
In [72]:
# Pass can be used in any code block statements: loops, classes (later), functions, etc. 

print("Start")
for r in range(10):
    pass 
print("Done")
Start
Done

Module Basics

As stated earlier, Python programs can be defined in .py files. These files are also known as modules. A module is a file containing Python definitions and statements. The file name is the module name minus the .py suffix.

What if you want these files to interact with each other (i.e., call functions, use variables from different modules)?

  • Modules import other modules by using the import statement.
     - ``import module_name`` 
     -  Import statements should be placed at the beginning of a python file. 
  • Once imported, you can access the definitions and statements within the module.
     - default way to access variabls, and statements is to use dot notation, where you specify the name of the module followed by a period, and then the code you want to access. 
      - ``module_name.variable`` or ``module_name.func(arg1,arg2,...)`` 

Python provides an extensive amount of predefined modules as part of its standard library. We will look at the math module and see how we can import and use the code within that module.

In [62]:
# 1st import the math module 
import math 

print(math.pi)          # Print the constant PI from the math module.
print(math.fabs(-232))  # Call the floating point abs function from the math module 
3.141592653589793
232.0

In the following weeks, we will learn more about modules and ways to use them efficiently.