Difference between revisions of "OPS435 Python Lab 4"

From CDOT Wiki
Jump to: navigation, search
(PART 3 - String Formatting Advanced Features)
 
(57 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 +
<font color='red'>
 +
'''** DO NOT USE - TO BE UPDATED FOR CENTOS 8.0 **'''
 +
</font>
 
= OBJECTIVES =
 
= OBJECTIVES =
  
:This lab will provide you will additional scripting tools to help us write even more effective Python scripts to be applied to practical application involving VM management and deployment in future labs.
+
:The '''first investigation''' in this lab will focus on '''Data Structures'''. Each data structure has its own advantages and limitations. This lab will emphasize the most important differences between them.  
  
:The '''first investigation''' in this lab will focus on '''Data Structures'''. In Wikipedia (http://searchsqlserver.techtarget.com/definition/data-structure)<br>''"A data structure is defined as a specialized format for organizing and storing data.  Any data structure is designed to organize data to suit a specific purpose so that it can be accessed and worked with in appropriate ways."''
+
:The '''second investigation''' will focus on strings. You have been using and storing strings since our first class, however in this lab we will dive into the more complex nature of string manipulation. Finally, this lab will cover how to use a variety of regular expression functions for searching and input validation.
 
 
:Each data structure has its own advantages and limitations. This lab will emphasize the most important differences as they relate to Python scripting.
 
 
 
:The '''second investigation''' will focus closely on strings. You have been using and storing strings since our first class, however in this lab we will dive into the more complex nature of string manipulation. Finally, this lab will cover how to use a variety of different regular expression functions, for searching and input validation.
 
  
 
=== PYTHON REFERENCE ===
 
=== PYTHON REFERENCE ===
  
:As you develop your Python scripting skills, you may start to be "overwhelmed" with the volume of information that you have absorbed over these labs. One way to help, is to write what you have learned in your labs into your lab logbook. Also, in programming, it is important to use online references in order to obtain information regarding Python scripting techniques and tools.
+
:As you develop your Python scripting skills, you may start to be "overwhelmed" with the volume of information that you have absorbed over these labs. One way to help is to learn to use online references effectively in order to obtain information regarding Python scripting techniques and tools.
  
 
:Below is a table with links to useful online Python reference sites (by category). You may find these references useful when performing assignments, etc.
 
:Below is a table with links to useful online Python reference sites (by category). You may find these references useful when performing assignments, etc.
Line 41: Line 40:
  
 
|}
 
|}
 
<br><br>
 
  
 
= INVESTIGATION 1: DATA STRUCTURES =
 
= INVESTIGATION 1: DATA STRUCTURES =
  
:In this investigation, you will learn several tools when using data structures in Python scripting.
+
:In this investigation, you will learn several data structures commonly used in Python scripting. These tools include '''lists''', '''tuples''', '''sets''', and '''dictionaries'''.
:These tools include '''tuples''', '''sets''', '''dictionaries''', and more '''advanced list functions'''.
 
 
   
 
   
 
== PART 1 - Tuples ==
 
== PART 1 - Tuples ==
  
:Many often confuse a '''tuple''' with a '''list''' (which you learned about in a previous lab). A '''tuple''' is a type of list whose values cannot be changes. In fact, the structure of a tuple cannot be changed (like adding, removing list elements).  
+
:Many often confuse a '''tuple''' with a '''list''' (which you learned about in a previous lab). A '''tuple''' is a type of list whose values cannot be changed. In fact, nothing in a tuple can be changed after it's created (like adding, removing list elements).  
  
 
:There are many advantages to using tuples when creating Python scripts:
 
:There are many advantages to using tuples when creating Python scripts:
  
::*'''Data protection''' (eg. values are are NOT allowed to change like income tax rate, social insurance number, etc)
+
::*'''Data protection''' (eg. values are are NOT allowed to change so you won't modify them accidentally)
::*The data structure in a tuple cannot be changed (eg. '''structure cannot be corrupted''')
 
 
::*Tuples can be used as '''keys in data dictionaries''' (which are NOT allowed to change)
 
::*Tuples can be used as '''keys in data dictionaries''' (which are NOT allowed to change)
 
::*Tuples allow for '''faster access''' than lists
 
::*Tuples allow for '''faster access''' than lists
  
:Term to indicate that a data structure cannot be changed is called '''immutable''' (as opposed to ''"mutable"'' which means the data structure can be changed).
+
:The term to indicate that a data structure cannot be changed is called '''immutable''' (as opposed to ''"mutable"'' which means the data structure can be changed).
  
 
:'''Perform the Following Steps:'''
 
:'''Perform the Following Steps:'''
:#Launch your ipython3 shell:<source>
+
:#Let's create two tuples in a temporary Python file, so we can learn how to use them and learn how they differ from lists.<br><br>Note: '''tuples are defined by using parenthesis ( )''' as opposed to '''lists which are defined by using square brackets [ ]'''<source lang="python">
ipython3
 
</source>Let's create two tuples, so we can learn how to use them and learn how they differ from lists.<br><br>Note: '''tuples are defined by using parenthesis ( )''' as opposed to '''lists are defined by using square brackets [ ]'''<br><br>
 
:#Issue the following:<source>
 
 
t1 = ('Prime', 'Ix', 'Secundus', 'Caladan')
 
t1 = ('Prime', 'Ix', 'Secundus', 'Caladan')
 
t2 = (1, 2, 3, 4, 5, 6)
 
t2 = (1, 2, 3, 4, 5, 6)
 
</source>
 
</source>
:#Values from a tuple can be retrieved in the same way as a list. For example, issue the following:<source>
+
:#Values from a tuple can be retrieved in the same way as a list. For example:<source lang="python">
t1[0]
+
print(t1[0])
t2[2:4]
+
print(t2[2:4])
 
</source>
 
</source>
:#You can also check to see whether a value exists inside a tuple or not. To demonstrate, issue the following:<source>
+
:#You can also check to see whether a value exists inside a tuple or not. To demonstrate try:<source lang="python">
'Ix' in t1
+
print('Ix' in t1)
'Geidi' in t1
+
print('Geidi' in t1)
</source>Let's now see how a tuple differs from a list. We will now create a list and note the difference between them.<br><br>
+
</source>Let's now see how a tuple differs from a list. We will now create a list and note the difference between them:<source lang="python">
:#Issue the following to create a list:<source>
 
 
list2 = [ 'uli101', 'ops235', 'ops335', 'ops435', 'ops535', 'ops635' ]
 
list2 = [ 'uli101', 'ops235', 'ops335', 'ops435', 'ops535', 'ops635' ]
 
</source>
 
</source>
:#See if you can change the value of your list by issuing the following:<source>
+
:#See if you can change the value of your list:<source lang="python">
 
list2[0]= 'ica100'
 
list2[0]= 'ica100'
list2[0]
+
print(list2[0])
 
print(list2)
 
print(list2)
</source>.You should have been successful in changing the value of your list.<br><br>
+
</source>You should have been successful in changing the value of your list.<br><br>
:#Now, try changing the value of your previously-created tuple by issuing:<source>
+
:#Now, try changing the value of your previously-created tuple:<source lang="python">
 
t2[1] = 10
 
t2[1] = 10
 
</source>Did it work? Once created the tuple values will not be able to change.<br><br>If you would like a tuple with different values than the tuple you currently have, then you must create a new one.<br><br>
 
</source>Did it work? Once created the tuple values will not be able to change.<br><br>If you would like a tuple with different values than the tuple you currently have, then you must create a new one.<br><br>
:#To create a new tuple, issue the following:<source>
+
:#The following creates a new tuple (t3) with a contents from a slice of the t2 tuple. Slicing works the same way for tuples as for lists:<source lang="python">
 
t3 = t2[2:3]
 
t3 = t2[2:3]
 
</source>
 
</source>
:#You can use most of the basic operations with tuples as you did with lists.<br><br>
+
:#Also, as with lists, you can use for loops to iterate the values of tuples:<source lang="python">
:#To demonstrate, issue the following:<source>
 
len(t1)    # list the length of the tuple
 
t1 * 3      # repetition
 
t1 + t2    # concatenation, remember this is creating a new tuple, not modifying
 
</source>
 
:#Also, as with lists, you can use loops with tuples. Issue the following to demonstrate:<source>
 
 
for item in t1:
 
for item in t1:
 
     print('item: ' + item)
 
     print('item: ' + item)
Line 112: Line 97:
 
::*Sets '''cannot contain duplicate values'''
 
::*Sets '''cannot contain duplicate values'''
  
:Since new duplicate entries will be automatically removed when using sets, they are very useful for performing tasks such as '''comparisons''': '''finding similarities or differences in multiple sets'''. Also, sets are considered to be fast!
+
:Since new duplicate entries will be automatically removed when using sets, they are very useful for performing tasks such as '''comparisons''': '''finding similarities or differences in multiple sets'''.
  
:'''Perform the Following Steps:'''
+
:#Create some sets to work with in a temporary Python file:<source lang="python">
:#Within your ipython3 shell, create a few sets to work with by issuing the following:<source>
 
 
s1 = {'Prime', 'Ix', 'Secundus', 'Caladan'}
 
s1 = {'Prime', 'Ix', 'Secundus', 'Caladan'}
 
s2 = {1, 2, 3, 4, 5}
 
s2 = {1, 2, 3, 4, 5}
 
s3 = {4, 5, 6, 7, 8}
 
s3 = {4, 5, 6, 7, 8}
</source>Note: '''Sets are defined by using braces { }''' as opposed to tuples that use parenthesis ( ), or lists that use square brackets [ ]'''<br><br>
+
</source>Note: '''Sets are defined by using braces { }''' as opposed to tuples which use parenthesis ( ), or lists which use square brackets [ ]'''<br /><br />
:#Try to issue the following to access a set through the index.<source>
+
:#Try to access a set through the index:<source lang="python">
s1[0]
+
print(s1[0])
</source>This should have created an '''error''', this is not how to access data inside a set because they are '''un-ordered'''. Instead, you should use the method (used in the previous section) to check to see if a value is contained within the set.<br><br>
+
</source>This should have caused an '''error'''. You cannot access data inside a set this way because the elements inside are '''unordered'''. Instead, you should use the '''in''' method to check to see whether a value is contained in the set:<source lang="python">
:#To demonstrate, issue the following:<source>
+
print('Ix' in s1)
'Ix' in s1
+
print('Geidi' in s1)
'Geidi' in s1
 
 
</source><br>'''Sets can be combined''', but it is important to note that any '''duplicate values (shared among sets) will be deleted'''.<br><br>
 
</source><br>'''Sets can be combined''', but it is important to note that any '''duplicate values (shared among sets) will be deleted'''.<br><br>
:#Issue the following, and note the items (and values) that are common to the following sets:<source>
+
:#Print the contents of the sets and note the values that are common:<source lang="python">
s2
+
print(s2)
s3
+
print(s3)
 
</source>
 
</source>
:#Now, issue the following to return a set containing only UNIQUE values (no duplicates) from both sets:<source>
+
:#This is how you get a set containing only UNIQUE values (no duplicates) from both sets:<source>
s2 | s3        # returns a set containing all values from both sets
+
print(s2 | s3)         # returns a set containing all values from both sets
s2.union(s3)    # same as s2 | s3
+
print(s2.union(s3))    # same as s2 | s3
</source>Notice that both methods above provides the same result, but the first method requires less keystrokes.<br><br>Instead of combining sets, we can display '''values that are common to both sets'''. This is known in mathematical terms as an '''intersection''' between the lists.<br><br>
+
</source>Notice that both methods above have the same result, which one you choose depends purely on your style.<br><br>Instead of combining sets, we can display '''values that are common to both sets'''. This is known in mathematical terms as an '''intersection''' between the lists:<source lang="python">
:#To demonstrate intersection between sets s2 and s3, issue the following:<source>
+
print(s2 & s3)             # returns a set containing all values that s2 and s3 share
s2 & s3            # returns a set containing all values that s2 and s3 share
+
print(s2.intersection(s3)) # same as s2 & s3
s2.intersection(s3) # same as s2 & s3
 
 
</source>
 
</source>
:#Sets can also have their values compared against other sets. First find out what items are in '''s2''' but not in '''s3'''. This is also called a '''difference'''. But notice that it only shows values that '''s2''' contains, specifically values that '''s3''' doesn't have. So this isn't really the <u>true</u> difference between the sets.<source>
+
:#Sets can also have their values compared against other sets. First find out what items are in '''s2''' but not in '''s3'''. This is also called a '''difference''':<source lang="python">
s2
+
print(s2)
s3
+
print(s3)
s2 - s3            # returns a set containing all values in s2 that are not found s3
+
print(s2 - s3)             # returns a set containing all values in s2 that are not found in s3
s2.difference(s3)  # same as s2 - s3
+
print(s2.difference(s3))  # same as s2 - s3
 
</source>
 
</source>
:#In order to see <u>every</u> difference between both sets, you need to find the '''symmetric difference'''. This will return a set that shows all numbers that both sets do not share together.<br><br>
+
:#In order to see <u>every</u> difference between both sets, you need to find the '''symmetric difference'''. This will return a set that shows all numbers that both sets do not share together:<source lang="python">
:#To demonstrate, issue the following:<source>
+
print(s2 ^ s3)                     # returns a set containing all values that both sets DO NOT share
s2 ^ s3                    # returns a set containing all values that both sets DO NOT share
+
print(s2.symmetric_difference(s3)) # same as s2 ^ s3
s2.symmetric_difference(s3) # same as s2 ^ s3
+
</source>Note: the '''set()''' function can convert lists into sets, and the '''list()''' function can convert sets into lists. The operations in this section can only be applied to sets, so if you need to perform a union, intersection, or difference between lists, you need to convert them to sets first. For example:<source lang="python">
</source>Note: the '''set()''' function can make lists into sets, and the '''list()''' function can make sets into lists<br><br>These powerful features can be useful and efficient. Unfortunately, lists <u>cannot</u> perform these operations, unless we have to convert the lists into sets. In order to that, you should first perform a comparison, then convert the list to a set.<br><br>There are two problems with performing the above-mentioned technique:
 
::::*Sets are '''un-ordered''' so if the list order is important this will cause problems and remove order
 
::::*Sets '''cannot contain duplicate values''', if the list contains any duplicate values they will be deleted.
 
 
 
:::However, if the list does not have any of the above requirements this is a great solution to some problems.
 
 
 
 
 
:::10. To demonstrate, issue the following:<source>
 
 
l2 = [1, 2, 3, 4, 5]
 
l2 = [1, 2, 3, 4, 5]
 
l3 = [4, 5, 6, 7, 8]
 
l3 = [4, 5, 6, 7, 8]
new_list = list(set(l2).intersection(set(l3)))  # '''set()''' can make lists into sets. '''list()''' can make sets into lists
+
temporary_set = set(l2).intersection(set(l3))
new_list
+
new_list = list(temporary_set)  # '''set()''' can make lists into sets. '''list()''' can make sets into lists.
 +
print(new_list)
 
</source>
 
</source>
  
'''Create a Python Script Demonstrating Comparing Sets'''
+
=== Create a Python Script Demonstrating Comparing Sets ===
 
:'''Perform the Following Instructions'''
 
:'''Perform the Following Instructions'''
::#Create the '''~/ops435/lab4/lab4a.py''' script. The purpose of this script will be to demonstrate the different way of comparing sets. There will be three functions, each returning a different set comparison.  
+
:#Create the '''~/ops435/lab4/lab4a.py''' script. The purpose of this script will be to demonstrate the different way of comparing sets. There will be three functions, each returning a different set comparison.  
::#Use the following template to get started:<source>
+
:#Use the following template to get started:<source lang="python">
 
#!/usr/bin/env python3
 
#!/usr/bin/env python3
  
def join_sets(set1, set2):
+
def join_sets(s1, s2):
     # join_sets will return a set that has every value from both set1 and set2 inside it
+
     # join_sets will return a set that contains every value from both s1 and s2
  
def match_sets(set1, set2):
+
def match_sets(s1, s2):
     # match_sets will return a set that contains all values found in both set1 and set2
+
     # match_sets will return a set that contains all values found in both s1 and s2
  
def diff_sets(set1, set2):
+
def diff_sets(s1, s2):
 
     # diff_sets will return a set that contains all different values which are not shared between the sets
 
     # diff_sets will return a set that contains all different values which are not shared between the sets
  
Line 189: Line 164:
 
</source>
 
</source>
  
:::*The match_sets() function should return a set that contains all values found in both sets
+
::*The join_sets() function should return a set that contains all values from both sets
:::*The diff_sets() function should return a set that contains all values which are not shared between both sets
+
::*The match_sets() function should return a set that contains all values found in both sets
:::*The join_sets() function should return a set that contains all values from both sets
+
::*The diff_sets() function should return a set that contains all values which are not shared between both sets
:::*All three functions should accept '''two arguments''' both are sets
+
::*All three functions should accept '''two arguments''' both are sets
:::*The script should show the exact output as the samples
+
::*The script should show the exact output as the samples
:::*The script should contain no errors
+
::*The script should contain no errors
  
::::'''Sample Run 1:'''<source>
+
:::'''Sample Run 1:'''<source>
run lab4a.py
+
./lab4a.py
 
set1:  {1, 2, 3, 4, 5, 6, 7, 8, 9}
 
set1:  {1, 2, 3, 4, 5, 6, 7, 8, 9}
 
set2:  {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
 
set2:  {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
Line 204: Line 179:
 
diff:  {1, 2, 3, 4, 10, 11, 12, 13, 14}
 
diff:  {1, 2, 3, 4, 10, 11, 12, 13, 14}
 
</source>
 
</source>
::::'''Sample Run 2 (with import):'''<source>
+
:::'''Sample Run 2 (with import):'''<source>
 
import lab4a
 
import lab4a
 
set1 = {1,2,3,4,5}
 
set1 = {1,2,3,4,5}
 
set2 = {2,1,0,-1,-2}
 
set2 = {2,1,0,-1,-2}
lab4a.join_sets(set1,set2)
+
print(lab4a.join_sets(set1,set2))
{-2, -1, 0, 1, 2, 3, 4, 5}
+
# Will output {-2, -1, 0, 1, 2, 3, 4, 5}
lab4a.match_sets(set1,set2)
+
print(lab4a.match_sets(set1,set2))
{1, 2}
+
# Will output {1, 2}
lab4a.diff_sets(set1,set2)
+
print(lab4a.diff_sets(set1,set2))
{-2, -1, 0, 3, 4, 5}
+
# Will output {-2, -1, 0, 3, 4, 5}
 
</source>
 
</source>
:::3. Exit the ipython3 shell, download the checking script and check your work. Enter the following commands from the bash shell.<source>
+
<ol><li value='3' style="margin-left:25px;">Download the checking script and check your work. Enter the following commands from the bash shell:<source lang="bash">
 
cd ~/ops435/lab4/
 
cd ~/ops435/lab4/
 
pwd #confirm that you are in the right directory
 
pwd #confirm that you are in the right directory
ls CheckLab4.py || wget matrix.senecac.on.ca/~acoatley-willis/CheckLab4.py
+
ls CheckLab4.py || wget https://raw.githubusercontent.com/Seneca-CDOT/ops435/master/LabCheckScripts/CheckLab4.py
 
python3 ./CheckLab4.py -f -v lab4a
 
python3 ./CheckLab4.py -f -v lab4a
</source>
+
</source></li>
:::4. Before proceeding, make certain that you identify any and all errors in lab4a.py. When the checking script tells you everything is OK before proceeding to the next step.
+
<li style="margin-left:25px;">Before proceeding, make certain that you identify all errors in lab4a.py. When the checking script tells you everything is OK - proceed to the next step.</li></ol>
  
'''Create a Python Script Demonstrating Comparing Lists'''
+
=== Create a Python Script Demonstrating Comparing Lists ===
 
:'''Perform the Following Instructions'''
 
:'''Perform the Following Instructions'''
::#Create the '''~/ops435/lab4/lab4b.py''' script. The purpose of this script will be to improve the previous script to perform the same joins, matches, and diffs, but this time on lists.  
+
:#Create the '''~/ops435/lab4/lab4b.py''' script. The purpose of this script will be to improve the previous script to perform the same joins, matches, and diffs, but this time on lists.  
::#Use the following as a template:<source>
+
:#Use the following as a template:<source lang="python">
 
#!/usr/bin/env python3
 
#!/usr/bin/env python3
  
def join_lists(list1, list2):
+
def join_lists(l1, l2):
     # join_lists will return a list that contains every value from both list1 and list2 inside it
+
     # join_lists will return a list that contains every value from both l1 and l2
  
def match_lists(list1, list2):
+
def match_lists(l1, l2):
     # match_lists will return a list that contains all values found in both list1 and list2
+
     # match_lists will return a list that contains all values found in both l1 and l2
  
def diff_lists(list1, list2):
+
def diff_lists(l1, l2):
 
     # diff_lists will return a list that contains all different values, which are not shared between the lists
 
     # diff_lists will return a list that contains all different values, which are not shared between the lists
  
Line 247: Line 222:
 
     print('diff: ', diff_lists(list1, list2))
 
     print('diff: ', diff_lists(list1, list2))
 
</source>
 
</source>
:::*The match_lists() function should return a list that contains all values found in both lists
+
::*The match_lists() function should return a list that contains all values found in both lists
:::*The diff_lists() function should return a list that contains all values which are not shared between both lists
+
::*The diff_lists() function should return a list that contains all values which are not shared between both lists
:::*The join_lists() function should return a list that contains all values from both sets
+
::*The join_lists() function should return a list that contains all values from both lists
:::*All three functions should accept '''two arguments''' both are lists
+
::*All three functions should accept '''two arguments''' both are lists
:::*The script should show the exact output as the samples
+
::*The script should show the exact output as the samples
:::*The script should contain no errors
+
::*The script should contain no errors
::::'''Sample Run 1:'''<source>
+
:::'''Sample Run 1:'''<source>
run lab4b.py
+
./lab4b.py
 
list1:  [1, 2, 3, 4, 5, 6, 7, 8, 9]
 
list1:  [1, 2, 3, 4, 5, 6, 7, 8, 9]
 
list2:  [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
 
list2:  [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
 
join:  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
 
join:  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
match:  [8, 9, 5, 6, 7]
+
match:  [5, 6, 7, 8, 9]
 
diff:  [1, 2, 3, 4, 10, 11, 12, 13, 14]
 
diff:  [1, 2, 3, 4, 10, 11, 12, 13, 14]
 
</source>
 
</source>
  
::::'''Sample Run 2 (with import):'''<source>
+
:::'''Sample Run 2 (with import) under interactive python shell:'''<source>
 
import lab4b
 
import lab4b
 
list1 = [1,2,3,4,5]
 
list1 = [1,2,3,4,5]
 
list2 = [2,1,0,-1,-2]
 
list2 = [2,1,0,-1,-2]
join_lists(list1,list2)
+
print(lab4b.join_lists(list1,list2)))
[0, 1, 2, 3, 4, 5, -2, -1]
+
# Will output [0, 1, 2, 3, 4, 5, -2, -1]
match_lists(list1,list2)                                                                                                                
+
print(lab4b.match_lists(list1,list2))                                                                                                               
[8, 9, 5, 6, 7]
+
# Will output [1, 2]
diff_lists(list1,list2)                                                                                                                  
+
print(lab4b.diff_lists(list1,list2))                                                                                                                 
[1, 2, 3, 4, 10, 11, 12, 13, 14]
+
# Will output [0, 3, 4, 5, -2, -1]
 
</source>
 
</source>
:::3. Exit the ipython3 shell, download the checking script and check your work. Enter the following commands from the bash shell.<source>
+
::3. Download the checking script and check your work. Enter the following commands from the bash shell.<source lang="bash">
 
cd ~/ops435/lab4/
 
cd ~/ops435/lab4/
 
pwd #confirm that you are in the right directory
 
pwd #confirm that you are in the right directory
Line 279: Line 254:
 
python3 ./CheckLab4.py -f -v lab4b
 
python3 ./CheckLab4.py -f -v lab4b
 
</source>
 
</source>
:::4. Before proceeding, make certain that you identify any and all errors in lab4b.py. When the checking script tells you everything is OK before proceeding to the next step.
+
::4. Before proceeding, make certain that you identify all errors in lab4b.py. When the checking script tells you everything is OK - proceed to the next step.
<br><br>
 
  
 
== PART 3 - Dictionaries ==
 
== PART 3 - Dictionaries ==
  
::By now, you have probably been exposed to database terminology. For example, a '''database''' is a collection of ''related records''. In turn, '''records''' are a collection of ''related fields''. In order to access a record in a database, you would need to access it by '''key field(s)'''. In order words, those key field(s) are a '''key that unlocks the access to a record''' within a database.
+
::In Python, a '''dictionary''' is a set of key-value pairs. Dictionaries are '''unordered''', like sets, however any value can be retrieved from a dictionary if you know the key. This section will go over how to create, access, and change dictionaries, giving you a new powerful tool to store and manipulate data.
 
 
::In Python, a '''dictionary''' is a set of key-value pairs. Dictionaries are '''unordered''', like sets, however any value can be retrieved from a dictionary if you know the key. This section will go over how to create, access, and change dictionaries, providing a new powerful tool to store and manipulate data.
 
  
 
::'''Perform the Following Steps:'''
 
::'''Perform the Following Steps:'''
::#Launch the ipython3 shell:<source>
+
::#Let's begin by creating a new dictionary in a temporary Python file:<source lang="python">
ipython3
 
</source>
 
::#Let's begin by creating a new dictionary (for practice):<source>
 
 
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Postal Code': 'M3J3M6'}
 
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Postal Code': 'M3J3M6'}
</source>You should note that the syntax to define a dictionary is similar to defining sets (i.e. using '''{}''').<br>Unlike sets, dictionaries use '''<code>key:value</code>''' pairs within the dictionary, each ''key:value'' pair in turn, are separated by commas.<br><br>You can get help associated with your dictionary by using functions such as '''dir()''' and '''help()'''.<br><br>
+
</source>You should note that the syntax to define a dictionary is similar to defining sets (i.e. using '''{}'''), but unlike sets dictionaries use '''<code>key:value</code>''' pairs within the dictionary, each ''key:value'' pair is separated by commas.
::#Issue the following and note all the available functions available and how to obtain assistance with dictionary objects:<source>
+
::#All the values in a dictionary can be retrieved by using the '''dictionary.values()''' function. This particular function provides a '''list''' containing all values:<source lang="python">
dir(dict_york)
+
print(dict_york.values())
help(dict_york)
+
</source>All keys to access the ''key:pair'' values within a dictionary can be retrieved using the '''dictionary.keys()''' function:<source lang="python">
</source>All values can be viewed by using the '''dictionary.values()''' function. This particular function provides a '''list''' containing all values.<br><br>
 
::#To demonstrate, issue the following:<source>
 
help(dict_york.values)
 
dict_york.values()
 
</source>All keys to access the ''key:pair'' values within a dictionary can be viewed by using the '''dictionary.keys()''' function. This function provides a '''list''' containing all keys<br><br>
 
::#To demonstrate this, issue the following:<source>
 
help(dict_york.keys)
 
 
dict_york.keys()
 
dict_york.keys()
</source>Armed with this information, We can retrieve <u>individual</u> values from a dictionary by provide the key associated with the key:pair value<br><br>
+
</source>We can retrieve <u>individual</u> values from a dictionary by providing the key associated with the value:<source lang="python">
::#For example, issue the following:<source>
+
print(dict_york['Address'])
dict_york['Address']
+
print(dict_york['Postal Code'])
dict_york['Postal Code']
 
 
</source>
 
</source>
::#Dictionary keys can be any '''immutable''' values (i.e. not permitted for value to be changed). Types of values include: '''strings''', '''numbers''', and '''tuples'''. Trying adding a couple new keys and values to the dictionary by issuing:<source>
+
::#Dictionary keys can be any '''immutable''' values (i.e. not permitted for value to be changed). Types of values include: '''strings''', '''numbers''', and '''tuples'''.
 +
::#Try adding a new key and value to the dictionary:<source lang="python">
 
dict_york['Country'] = 'Canada'
 
dict_york['Country'] = 'Canada'
dict_york
+
print(dict_york)
dict_york.values()
+
print(dict_york.values())
dict_york.keys()
+
print(dict_york.keys())
 
</source>
 
</source>
::#Let's add another key:value pair to our dictionary to change the province key:pair value to BC:<source>
+
::#Let's change the province value to BC:<source lang="python">
 
dict_york['Province'] = 'BC'
 
dict_york['Province'] = 'BC'
dict_york
+
print(dict_york)
dict_york.values()
+
print(dict_york.values())
dict_york.keys()
+
print(dict_york.keys())
</source>'''WARNING: Dictionary keys must be unique'''. Attempting to add a key that already exists in the dictionary will <u>overwrite</u> the existing value for that key!<br><br>
+
</source>'''WARNING: Dictionary keys must be unique'''. Attempting to add a key that already exists in the dictionary will <u>overwrite</u> the existing value for that key! For example:<source lang="python">
::#To demonstrate, issue the following:<source>
 
 
dict_york['Province'] = 'ON'
 
dict_york['Province'] = 'ON'
dict_york
+
print(dict_york)
dict_york.values()
+
print(dict_york.values())
dict_york.keys()
+
print(dict_york.keys())
</source>You should notice that key value for 'Province' has been changed back to 'ON'.<br><br>These lists that contain the values and keys of the dictionary are not <u>real</u> python lists - they are "views of the dictionary" and therefore are <u>immutable</u>. You could change these views into usable lists by using the '''list()''' function (where the index can be used to access individual values).<br><br>
+
</source>You should notice that value for the 'Province' key has been changed back to 'ON'.<br><br>The lists that contain the values and keys of the dictionary are not <u>real</u> python lists - they are "views of the dictionary" and therefore are <u>immutable</u>. You could change these views into usable lists by using the '''list()''' function:<source lang="python">
::#For example, issue the following:<source>
 
 
list_of_keys = list(dict_york.keys())
 
list_of_keys = list(dict_york.keys())
list_of_keys[0]
+
print(list_of_keys[0])
 
</source>
 
</source>
::#In addition, lists can be changed into sets if we would like to perform comparisons with another set. To demonstrate, issue the following:<source>
+
::#Lists can be used with '''for loops''':<source lang="python">
set_of_keys = set(dict_york.keys())
 
set_of_values = set(dict_york.values())
 
set_of_keys | set_of_values
 
</source>
 
::#Lists can be used with '''for loops'''. To Demonstrate, issue the following:<source>
 
 
list_of_keys = list(dict_york.keys())
 
list_of_keys = list(dict_york.keys())
 
for key in list_of_keys:
 
for key in list_of_keys:
 
     print(key)
 
     print(key)
for value in dict_york.values()
+
for value in dict_york.values():
 
     print(value)
 
     print(value)
</source>Additional Information regarding Dictionaries:<ul><li>The values and keys can be looped over using the index as well
 
::#The '''range()''' function provides a list of numbers in a range.</li><li>The '''len()''' function provides a the number of items in a list.</li><li>Used together '''len()''' and '''range()''' can be used to create a list of usable indexes for a specific list</li></ul><br>Let's create a dictionary by using lists in order to store our dictionary data. First, we need to  pair the keys and values of two separate lists.<br><br>
 
::#Issue the following:<source>
 
list_of_keys = list(dict_york.keys())
 
list_of_values = list(dict_york.values())
 
list_of_indexes = range(0, len(dict_york.keys()))
 
list_of_indexes
 
list_of_keys[0]
 
list_of_values[0]
 
</source>Now, let's use these '''newly-created lists''', '''len()''' &amp; '''range()''' functions with a '''for loop''' to construct our dictionary:<br><br>
 
::#Issue the following:<source>
 
list_of_keys = list(dict_york.keys())
 
list_of_values = list(dict_york.values())
 
for index in range(0, len(list_of_keys)):
 
    print(list_of_keys[index] + '--->' + list_of_values[index])
 
 
</source>
 
</source>
::#Looping using indexes is not the best way to loop through a dictionary. A new dictionary could be created using this method, but this is '''not good''':<source>
+
 
list_of_keys = list(dict_york.keys())
+
=== Create a Python Script for Managing Dictionaries ===
list_of_values = list(dict_york.values())
 
new_dictionary = {}
 
for index in range(0, len(list_of_keys)):
 
    new_dictionary[list_of_keys[index]] = list_of_values[index]
 
</source>
 
::#The above method uses a lot of memory and loops. The best method to create a dictionary from two lists is to use the zip() function:<source>
 
list_of_keys = list(dict_york.keys())
 
list_of_values = list(dict_york.values())
 
new_dictionary = dict(zip(list_of_keys, list_of_values))
 
</source>
 
::#Looping through the keys in a dictionary also provides a easy way to get the value for each key at the same time:<source>
 
for key in dict_york.keys():
 
    print(key + '--->' + dict_york[key])
 
</source>
 
::#An alternative (possibly more efficient) method would be to cause both the key and its value to be extracted into a single (using a for loop, and using a special object):<source>
 
for key, value in dict_york.items():
 
    print(key + ' | ' + value)
 
</source>
 
'''Create a Python Script for Managing Dictionaries'''
 
 
:'''Perform the Following Instructions'''
 
:'''Perform the Following Instructions'''
 
::#Create the '''~/ops435/lab4/lab4c.py''' script. The purpose of this script will be to create dictionaries, extract data from dictionaries, and to make comparisons between dictionaries.  
 
::#Create the '''~/ops435/lab4/lab4c.py''' script. The purpose of this script will be to create dictionaries, extract data from dictionaries, and to make comparisons between dictionaries.  
::#Use the following as a template:<source>
+
::#Use the following as a template:<source lang="python">
 
#!/usr/bin/env python3
 
#!/usr/bin/env python3
  
Line 396: Line 317:
 
     # Place code here - refer to function specifics in section below
 
     # Place code here - refer to function specifics in section below
  
def split_dictionary(dictionary):
 
    # Place code here - refer to function specifics in section below
 
     
 
 
def shared_values(dict1, dict2):
 
def shared_values(dict1, dict2):
 
     # Place code here - refer to function specifics in section below
 
     # Place code here - refer to function specifics in section below
Line 406: Line 324:
 
     york = create_dictionary(list_keys, list_values)
 
     york = create_dictionary(list_keys, list_values)
 
     print('York: ', york)
 
     print('York: ', york)
    keys, values = split_dictionary(dict_newnham)
 
    print('Newnham Keys: ', keys)
 
    print('Newnham Values: ', values)
 
    keys, values = split_dictionary(york)
 
    print('York Keys: ', keys)
 
    print('York Values: ', values)
 
 
     common = shared_values(dict_york, dict_newnham)
 
     common = shared_values(dict_york, dict_newnham)
 
     print('Shared Values', common)
 
     print('Shared Values', common)
 
</source>
 
</source>
  
:::*The script should contain '''three''' functions:
+
:::*The script should contain '''two''' functions:
:::::'''create_dictionary()'''<ol><li>'''accepts''' two lists as arguments keys and values, '''combines''' these lists together to '''create''' a dictionary</li><li>'''returns a dictionary''' that has the keys and associated values from the lists</li></ol>
+
:::::'''create_dictionary()'''<ol><li>'''accepts''' two lists as arguments keys and values, '''combines''' these lists together to '''create''' a dictionary<br>('''Tip:''' use a while loop to access elements in both the keys and values lists at the same time)</li><li>'''returns a dictionary''' that has the keys and associated values from the lists</li></ol>
:::::'''split_dictionary()'''<ol><li>'''accepts''' a single dictionary as a argument and '''splits''' the dictionary into two lists, keys and values</li><li>'''returns two lists''': The return function can return multiple lists (separated by a comma). In our case, use: '''return keys, values'''</li></ol>
 
 
:::::'''shared_values()''' <ol><li>'''accepts''' two dictionaries as arguments and '''finds''' all values that are shared between the two dictionaries<br>('''Tip:''' generate sets containing only values for each dictionary, then use a function mentioned in a previous section to store the values that are common to <u>both</u> lists)</li><li>'''returns a set''' containing '''ONLY values''' found in '''BOTH dictionaries'''</li></ol>
 
:::::'''shared_values()''' <ol><li>'''accepts''' two dictionaries as arguments and '''finds''' all values that are shared between the two dictionaries<br>('''Tip:''' generate sets containing only values for each dictionary, then use a function mentioned in a previous section to store the values that are common to <u>both</u> lists)</li><li>'''returns a set''' containing '''ONLY values''' found in '''BOTH dictionaries'''</li></ol>
 
:::*make sure the functions have the correct number of arguments required
 
:::*make sure the functions have the correct number of arguments required
Line 424: Line 335:
 
:::*The script should contain no errors
 
:::*The script should contain no errors
 
::::'''Sample Run 1:'''<source>
 
::::'''Sample Run 1:'''<source>
run lab4c.py
+
./lab4c.py
 
York:  {'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Address': '70 The Pond Rd', 'Province': 'ON', 'City': 'Toronto'}
 
York:  {'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Address': '70 The Pond Rd', 'Province': 'ON', 'City': 'Toronto'}
Newnham Keys:  ['Country', 'Postal Code', 'Address', 'Province', 'City']
 
Newnham Values:  ['Canada', 'M2J2X5', '1750 Finch Ave E', 'ON', 'Toronto']
 
York Keys:  ['Country', 'Postal Code', 'Address', 'Province', 'City']
 
York Values:  ['Canada', 'M3J3M6', '70 The Pond Rd', 'ON', 'Toronto']
 
 
Shared Values {'Canada', 'ON', 'Toronto'}
 
Shared Values {'Canada', 'ON', 'Toronto'}
 
</source>
 
</source>
::::'''Sample Run 2(with import):'''<source>
+
::::'''Sample Run 2 (with import):'''<source>
 
import lab4c
 
import lab4c
 
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
 
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
Line 439: Line 346:
 
list_values = ['70 The Pond Rd', 'Toronto', 'Canada', 'M3J3M6', 'ON']
 
list_values = ['70 The Pond Rd', 'Toronto', 'Canada', 'M3J3M6', 'ON']
  
york = create_dictionary(list_keys, list_values)
+
york = lab4c.create_dictionary(list_keys, list_values)
  
york
+
print(york)
{'Address': '70 The Pond Rd',
+
# Will print: {'Address': '70 The Pond Rd',
'City': 'Toronto',
+
              'City': 'Toronto',
'Country': 'Canada',
+
              'Country': 'Canada',
'Postal Code': 'M3J3M6',
+
              'Postal Code': 'M3J3M6',
'Province': 'ON'}
+
              'Province': 'ON'}
  
keys, values = split_dictionary(dict_newnham)
+
common = lab4c.shared_values(dict_york, dict_newnham)
  
keys
+
print(common)
['Country', 'Postal Code', 'Address', 'Province', 'City']
+
# Will print: {'Canada', 'ON', 'Toronto'}
 
 
values
 
['Canada', 'M2J2X5', '1750 Finch Ave E', 'ON', 'Toronto']
 
 
 
keys, values = split_dictionary(york)
 
 
 
keys
 
['Country', 'Postal Code', 'Address', 'Province', 'City']
 
 
 
values
 
['Canada', 'M3J3M6', '70 The Pond Rd', 'ON', 'Toronto']
 
 
 
common = shared_values(dict_york, dict_newnham)
 
 
 
common
 
{'Canada', 'ON', 'Toronto'}
 
 
</source>
 
</source>
:::3. Exit the ipython3 shell, download the checking script and check your work. Enter the following commands from the bash shell.<source>
+
:::3. Download the checking script and check your work. Enter the following commands from the bash shell.<source lang="bash">
 
cd ~/ops435/lab4/
 
cd ~/ops435/lab4/
 
pwd #confirm that you are in the right directory
 
pwd #confirm that you are in the right directory
ls CheckLab4.py || wget matrix.senecac.on.ca/~acoatley-willis/CheckLab4.py
+
ls CheckLab4.py || wget https://raw.githubusercontent.com/Seneca-CDOT/ops435/master/LabCheckScripts/CheckLab4.py
 
python3 ./CheckLab4.py -f -v lab4c
 
python3 ./CheckLab4.py -f -v lab4c
 
</source>
 
</source>
:::4. Before proceeding, make certain that you identify any and all errors in lab4c.py. When the checking script tells you everything is OK before proceeding to the next step.
+
:::4. Before proceeding, make certain that you identify all errors in lab4c.py. When the checking script tells you everything is OK proceed to the next step.
<br><br>
 
 
 
== PART 4 - List Comprehension ==
 
 
 
:We have already have had an introduction to lists. We will now explore advanced functions that use and generate lists. This is a very common practice in Python: understanding how to generate, manipulate, and apply functions to items inside a list can be incredibly useful. List comprehension is a way to build new lists from existing list and to do it faster than simply looping over lists.
 
 
 
:'''Perform the Following Steps'''
 
 
 
:#Let's start by creating a list and then applying some functions to each item in that list. Issue the following to create a list and then display the square for each item within that list:<source>
 
l1 = [1, 2, 3, 4, 5]
 
for item in l1:
 
    print(item ** 2)
 
</source>In order to store these results (i.e. squares) for later use, you would have to create a new list and append the squares to it. This will generate a new list that contains squared values in the same positions of the first list. In this way, you are using an existing list in order to create a new (larger) list.<br><br>
 
:#To demonstrate, issue the following:<source>
 
l1 = [1, 2, 3, 4, 5]
 
l2 = []
 
for item in l1:
 
    l2.append(item ** 2)
 
l1
 
l2
 
</source>Since this may be a repetitive task, it makes more sense to create a function that will append the squares to a new item within an existing list.<br><br>
 
:#Issue the following to see how that can be performed:<source>
 
def square(number):
 
    return number ** 2
 
 
 
l1 = [1, 2, 3, 4, 5]
 
l2 = []
 
for item in l1:
 
    l2.append(square(item))
 
 
 
l1
 
l2
 
</source>The '''map()''' function can be used to apply a function on each item in a list. This is exactly what happened in the previous example; however, using the ''map()'' function provides for better syntax, and removes the loop (including the variable that was created inside the loop). Therefore, using the ''map()'' function will make your Python script more efficient while performing the same task.<br><br>
 
:#To demonstrate, issue the following:<source>
 
def square(number):
 
    return number ** 2
 
 
 
l1 = [1,2,3,4,5]
 
l2 = list(map(square, l1))
 
 
 
l1
 
l2
 
</source>The above ''map()'' function requires another function as well as a list. This means that before using (calling) the map() function, that other function would have to have been defined earlier in the script. This entire process can be avoided through the use of '''anonymous functions'''. This is the ability to create a simple function without defining it, and pass it on to other function calls. You will use the the '''lambda anonymous function''', which will return a function that you can use in that function immediately (i.e. without having to declare it in your script). The function takes 1 argument (called: x), and it will square that value.<br><br>
 
:#To demonstrate, issue the following:<source>
 
square = lambda x: x ** 2
 
l1 = [1,2,3,4,5]
 
l2 = list(map(square, l1))
 
 
 
l1
 
l2
 
</source>
 
:#The above code is actually not particularly good, the whole purpose of using lambda here is we were avoiding the function definition and just quickly returning a function. However this does break down exactly what lambda does, it returns a function for use. Fix this by removing the square function and just use the return function from lambda. Now remember what map requires? map's first argument is a function, and map's second argument is a list. Here lambda will return a function and provide it as the first argument.<source>
 
l1 = [1,2,3,4,5]
 
l2 = list(map(lambda x: x ** 2, l1))
 
 
 
l1
 
l2
 
</source>
 
:#Using the list comprehensions above our code will be faster and more efficient than using multiple variables and loops.
 
  
 
= INVESTIGATION 2: STRINGS =
 
= INVESTIGATION 2: STRINGS =
:Strings are basically a list of characters (bits of text). Strings store text so that they can be later for manipulation (by a wide range of functions). This section will investigate strings in more detail such as '''cutting strings into sub-strings''', '''joining strings''', '''formatting strings''', '''searching through strings''', and '''matching strings against patterns'''.<br><br>Strings are '''immutable''' data objects - this means that once a string is created, it <u>cannot</u> be modified. In order to make a change inside a string, you would first make a copy of the part of the string (i.e. sub-string) for manipulation.
+
:Strings are basically a list of characters (bits of text). This section will investigate strings in more detail such as '''cutting strings into sub-strings''', '''joining strings''', '''formatting strings''', '''searching through strings''', and '''matching strings against patterns'''.<br><br>Strings are '''immutable''' data objects - this means that once a string is created, it <u>cannot</u> be modified. In order to make a change inside a string, you would first make a copy of the part of the string (i.e. sub-string) for manipulation.
  
 
== PART 1 - Strings and Substrings ==
 
== PART 1 - Strings and Substrings ==
Line 543: Line 375:
  
 
:'''Perform the Following Steps:'''
 
:'''Perform the Following Steps:'''
:#Launch the ipython3 shell<source>
+
:#Create some strings in a temporary Python file:<source lang="python">
ipython3
 
</source>
 
:#Issue the following to create strings:<source>
 
 
course_name = 'Open System Automation'
 
course_name = 'Open System Automation'
 
course_code = 'OPS435'
 
course_code = 'OPS435'
course_number = '435'
+
course_number = 435
</source>Strings can contain any '''characters''' inside them, whether they are '''letters''', '''numbers''', or '''symbols'''. In our ipython3 shell the values inside each string variable can be seen just by typing the string variable name. However, when writing python scripts, these string variables should be placed inside '''print()''' functions in order to display on the screen.<br><br> Strings can also be '''concatenated''' (i.e. "combined together") by using the '''+''' sign, just make sure string are only concatenating other strings(no lists, no numbers, no dictionaries, etc.).<br><br>
+
</source>Strings can contain any '''characters''' inside them, whether they are '''letters''', '''numbers''', or '''symbols'''.
:#To demonstrate what was previously mentioned, issue the following:<source>
+
:#Strings can also be '''concatenated''' (i.e. "combined together") by using the '''+''' sign, just make sure string are only concatenating strings with strings (no lists, no numbers, no dictionaries, etc.):<source lang="python">
course_name
 
course_code
 
course_number
 
 
print(course_name)
 
print(course_name)
 
print(course_code)
 
print(course_code)
 
print(str(course_number))
 
print(str(course_number))
 
print(course_name + ' ' + course_code + ' ' + str(course_number))
 
print(course_name + ' ' + course_code + ' ' + str(course_number))
</source>Strings can also use special syntax for string '''repetition''' by <u>multiplying</u> the string by a number. This will repeat that string that many times. Repetition with '''*''' is useful whenever a string needs to be repeated more than once<br><br>
+
</source>When using the '''print()''' function, you can display '''special characters'''. One such special character is the  is the newline character (denoted by the symbol:  '''\n'''). This allows you to separate content between new lines or empty lines:<source lang="python">
:#Issue the following:<source>
 
print(course_name + '-' + course_code)
 
print(course_name + '-'*5 + course_code)
 
print(course_name + '-'*25 + course_code)
 
print('abc'*2)
 
print(course_code*5)
 
</source>When using the '''print()''' function, you can display '''special characters'''. One such special character is the  is the newline character (denoted by the symbol:  '''\n'''). This allows you to separate content between new lines or empty lines.<br><br>
 
:#To demonstrate, issue the following:<source>
 
 
print('Line 1\nLine 2\nLine 3\n')
 
print('Line 1\nLine 2\nLine 3\n')
 
</source>
 
</source>
:#By using both string repetition and a newline character, multiple lines can be created at once. Issue the following:<source>
+
:#Strings have many built-in functions that we can use to manipulate text. [https://docs.python.org/3/library/stdtypes.html#string-methods Here's a list].
print('Line 1' + '\n'*4 + 'Line 5\nLine 6')
+
:#Lets try out several different functions:<source lang="python">
 +
print(course_name.lower())        # Returns a string in lower-case letters
 +
print(course_name.upper())        # Returns a string in upper-case letters
 +
print(course_name.swapcase())      # Returns a string with upper-case and lower-case letters swapped
 +
print(course_name.title())        # Returns a string with upper-case first letter of each word, lowercase for remaining text
 +
print(course_name.capitalize())   # Returns a string with upper-case first letter only, lowercase for remaining text
 
</source>
 
</source>
:#Strings have many built-in functions that we can use to manipulate text. Let's take a look at the strings name space and the available functions:<source>
+
:#These values can be saved inside new strings and then reused:<source lang="python">
dir(course_name)
 
help(course_name)
 
</source>
 
:#Lets try out several different functions. Refer back to the '''help()''' function for more information, these are quick ways to view strings in different ways. Issue the following:<source>
 
course_name.lower()        # Returns a string in lower-case letters
 
course_name.upper()        # Returns a string in upper-case letters
 
course_name.swapcase()      # Returns a string with upper-case and lower-case letters swapped
 
course_name.title()        # Returns a string with upper-case first letter of each word, lowercase for remaining text
 
course_name.capitalize()    # Returns a string with upper-case first letter only, lowercase for remaining text
 
</source>
 
:#These values can be saved inside new strings and then reused:<source>
 
 
lower_name = course_name.lower()    # Save returned string lower-case string inside new string variable
 
lower_name = course_name.lower()    # Save returned string lower-case string inside new string variable
 
print(lower_name)
 
print(lower_name)
Line 591: Line 403:
 
lower_name.split(' ')      # Provide the split() function with a character to split on
 
lower_name.split(' ')      # Provide the split() function with a character to split on
 
</source>The above example will return a list of strings, which we can access just like all of lists. <br><br>
 
</source>The above example will return a list of strings, which we can access just like all of lists. <br><br>
:#Let's practice more string manipulation by issuing the following:<source>
+
:#Let's practice more string manipulation:<source lang="python">
 
list_of_strings = lower_name.split(' ')    # Split string on spaces and store the list in a variable
 
list_of_strings = lower_name.split(' ')    # Split string on spaces and store the list in a variable
list_of_strings                             # Display list
+
print(list_of_strings)                      # Display list
list_of_strings[0]                         # Display first item in list
+
print(list_of_strings[0])                  # Display first item in list
</source>Since lists are actually a list of '''strings''', you should be able to use any function that works with a string on a list.<br><br>
+
</source>Since lists are actually a list of '''strings''', you should be able to use any function that works with a string on a list:<source lang="python">
:#To demonstrate, issue the following:<source>
 
 
list_of_strings[0].upper()          # Use the function after the index to affect a single string within a list
 
list_of_strings[0].upper()          # Use the function after the index to affect a single string within a list
 
first_word = list_of_strings[0]
 
first_word = list_of_strings[0]
first_word
 
 
print(first_word)
 
print(first_word)
</source>The '''index''' that is used to access <u>items</u> within a list, can also be used to access <u>characters</u> within a string. For practice, let's  create a new string, and start accessing the strings index.<br><br>
+
</source>The '''index''' that is used to access <u>items</u> within a list, can also be used to access <u>characters</u> within a string. For practice, let's  create a new string, and start accessing the strings index:<source>
:#Issue the following:<source>
 
 
course_name = 'Open System Automation'
 
course_name = 'Open System Automation'
 
course_code = 'OPS435'
 
course_code = 'OPS435'
 
course_number = 435
 
course_number = 435
course_code[0]                          # Return a string that is the first character in course_code
+
print(course_code[0])                         # Print the first character in course_code
course_code[2]                          # Return a string that is the third character in course_code
+
print(course_code[2])                         # Print the third character in course_code
course_code[-1]                        # Return a string that is the last character in course_code
+
print(course_code[-1])                         # Print the last character in course_code
str(course_number)[0]                  # Turn the integer into a string, return first character in that string
+
print(str(course_number)[0])                   # Turn the integer into a string, return first character in that string, and print it
course_code[0] + course_code[1] + course_code[2]
+
print(course_code[0] + course_code[1] + course_code[2])
</source>You can use a technique that uses index numbers of a string to '''cut-out''' or '''"parse"''' smaller portions of text within a string. This term is referred to as a '''substring'''. We can use this to create a new string or display only a small portion of it<br><br>
+
</source>
:#To demonstrate, issue the following:<source>
+
:#You can use a technique that uses index numbers of a string to '''cut-out''' or '''"parse"''' smaller portions of text within a string. This term is referred to as a '''substring'''. We can use this to create a new string or display only a small portion of it:<source lang="python">
course_name[0:4]                       # Return the first four characters (values of index numbers 0,1,2, and 3)  
+
print(course_name[0:4])                # Print the first four characters (values of index numbers 0,1,2, and 3)  
 
first_word = course_name[0:4]          # Save this substring for later use
 
first_word = course_name[0:4]          # Save this substring for later use
course_code[0:3]                       # Return the first three characters (values of index numbers 0,1,and 2)
+
print(course_code[0:3])                # Print the first three characters (values of index numbers 0,1,and 2)
 
</source>
 
</source>
:# The index allows a few '''extra functions''' using the same parsing technique:<source>
+
:# The index allows a few '''extra functions''' using the same parsing technique:<source lang="python">
 
course_name = 'Open System Automation'
 
course_name = 'Open System Automation'
course_name[12:]                        # Return the substring '12' index until end of string
+
print(course_name[12:])                       # Print the substring '12' index until end of string
course_name[5:]                        # Return the substring '5' index until end of string
+
print(course_name[5:])                         # Print the substring '5' index until end of string
course_name[-1]                        # Return the last character
+
print(course_name[-1])                         # Print the last character
</source>With '''negative indexes''', '''-1''' index would represent the '''last''' character, '''-2''' index would represent the '''second last''' character, etc.<br><br>
+
</source>With '''negative indices''', '''-1''' would represent the '''last''' character, '''-2''' index would represent the '''second last''' character, etc.:<source lang="python">
:#To demonstrate, issue the following:<source>
 
 
course_name = 'Open System Automation'
 
course_name = 'Open System Automation'
course_name[-1]
+
print(course_name[-1])
course_name[-2]
+
print(course_name[-2])
 
</source>
 
</source>
:# Issue the following to practice some of the skills that you have learned in this section:<source>
+
:# Practice some of the skills that you have learned in this section:<source>
 
course_name = 'Open System Automation'
 
course_name = 'Open System Automation'
course_name[-10:]                                   # Return the last ten characters
+
print(course_name[-10:])                            # Return the last ten characters
course_name[-10:-6]                                 # Try and figure out what this is returning  
+
print(course_name[-10:-6])                          # Try and figure out what this is returning  
course_name[0:4] + course_name[-10:-6]             # Combine substrings together
+
print(course_name[0:4] + course_name[-10:-6])      # Combine substrings together
 
substring = course_name[0:4] + course_name[-10:-6]  # Save the combined substring as a new string for later
 
substring = course_name[0:4] + course_name[-10:-6]  # Save the combined substring as a new string for later
substring
+
print(substring)
 
</source>
 
</source>
 
:# The real power found in substrings goes beyond just manually writing index values and getting back words. The next part of this investigation will cover how to search through a string for a specific word, letter, number, and return the index to that search result.  
 
:# The real power found in substrings goes beyond just manually writing index values and getting back words. The next part of this investigation will cover how to search through a string for a specific word, letter, number, and return the index to that search result.  
Line 640: Line 448:
 
'''Create a Python Script Demostrating Substrings'''
 
'''Create a Python Script Demostrating Substrings'''
 
:'''Perform the Following Instructions'''
 
:'''Perform the Following Instructions'''
::#Create the '''~/ops435/lab4/lab4d.py''' script. The purpose of this script is to demonstrate creating and manipulating strings. There will be four functions each will return a single string.
+
:#Create the '''~/ops435/lab4/lab4d.py''' script. The purpose of this script is to demonstrate creating and manipulating strings. There will be four functions each will return a single string.
::#Use the following template to get started:<source>
+
:#Use the following template to get started:<source>
 
#!/usr/bin/env python3
 
#!/usr/bin/env python3
 
# Strings 1
 
# Strings 1
Line 675: Line 483:
 
</source>
 
</source>
  
:::*The script should contain '''four''' functions (use your own argument names):
+
::*The script should contain '''four''' functions (use your own argument names):
:::::'''first_five()''':<ol><li>Accepts a single string argument</li><li>Returns a string that contains the first five characters of the argument given</li></ol>
+
::::'''first_five()''':<ol><li>Accepts a single string argument</li><li>Returns a string that contains the first five characters of the argument given</li></ol>
:::::'''last_seven()''':<ol><li>Accepts a single string argument</li><li>Returns a string that contains the last seven characters of the argument given</li></ol>
+
::::'''last_seven()''':<ol><li>Accepts a single string argument</li><li>Returns a string that contains the last seven characters of the argument given</li></ol>
:::::'''middle_number()''':<ol><li>Accepts a integer as a argument</li><li>Returns a string containing the second and third characters in the number</li></ol>
+
::::'''middle_number()''':<ol><li>Accepts a integer as a argument</li><li>Returns a string containing the second and third characters in the number</li></ol>
:::::'''first_three_last_three()''':<ol><li>Accepts two string arguments</li><li>Returns a single string that starts with the first three characters of argument1 and ends with the last three characters of argument2</li></ol>
+
::::'''first_three_last_three()''':<ol><li>Accepts two string arguments</li><li>Returns a single string that starts with the first three characters of argument1 and ends with the last three characters of argument2</li></ol>
:::*Example: first_three_last_three('abcdefg', '1234567') returns single string 'abc567'
+
::*Example: first_three_last_three('abcdefg', '1234567') returns single string 'abc567'
::::'''Sample Run 1'''<source>
+
:::'''Sample Run 1'''<source>
run lab4d.py  
+
./lab4d.py  
 
Hello
 
Hello
 
Senec
 
Senec
Line 692: Line 500:
 
Send!!
 
Send!!
 
</source>
 
</source>
::::'''Sample Run 2(import)'''<source>
+
:::'''Sample Run 2 (with import)'''<source>
 
import lab4d
 
import lab4d
 +
 
str1 = 'Hello World!!'
 
str1 = 'Hello World!!'
 
str2 = 'Seneca College'
 
str2 = 'Seneca College'
 
num1 = 1500
 
num1 = 1500
 
num2 = 1.50
 
num2 = 1.50
lab4d.first_five(str1)
+
 
'Hello'
+
print(lab4d.first_five(str1))
lab4d.first_five(str2)
+
# Will output 'Hello'
'Senec'
+
print(lab4d.first_five(str2))
lab4d.last_seven(str1)
+
# Will output 'Senec'
'World!!'
+
print(lab4d.last_seven(str1))
lab4d.last_seven(str2)
+
# Will output 'World!!'
'College'
+
print(lab4d.last_seven(str2))
lab4d.middle_number(num1)
+
# Will output 'College'
'50'
+
print(lab4d.middle_number(num1))
lab4d.middle_number(num2)
+
# Will output '50'
'.5'
+
print(lab4d.middle_number(num2))
lab4d.first_three_last_three(str1, str2)
+
# Will output '.5'
'Helege'
+
print(lab4d.first_three_last_three(str1, str2))
lab4d.first_three_last_three(str2, str1)
+
# Will output 'Helege'
'Send!!'
+
print(lab4d.first_three_last_three(str2, str1))
 +
# Will output 'Send!!'
 
</source>
 
</source>
:::3. Exit the ipython3 shell, download the checking script and check your work. Enter the following commands from the bash shell.<source>
+
::3. Download the checking script and check your work. Enter the following commands from the bash shell.<source>
 
cd ~/ops435/lab4/
 
cd ~/ops435/lab4/
 
pwd #confirm that you are in the right directory
 
pwd #confirm that you are in the right directory
ls CheckLab4.py || wget matrix.senecac.on.ca/~acoatley-willis/CheckLab4.py
+
ls CheckLab4.py || wget https://raw.githubusercontent.com/Seneca-CDOT/ops435/master/LabCheckScripts/CheckLab4.py
 
python3 ./CheckLab4.py -f -v lab4d
 
python3 ./CheckLab4.py -f -v lab4d
 
</source>
 
</source>
:::4. Before proceeding, make certain that you identify any and all errors in lab4d.py. When the checking script tells you everything is OK before proceeding to the next step.
+
::4. Before proceeding, make certain that you identify all errors in lab4d.py. When the checking script tells you everything is OK - proceed to the next step.
 
 
== PART 2 - String Formatting Basic Fundamentals==
 
 
 
:In Python scripting, using plus signs and commas for string concatenation is very limited and can become messy when when used at length with many values and/or calculations. This section will cover the '''format()''' function that can be used with every type of string. This function allows the user of Python to create well formatted code, to align text, and to convert values efficiently and cleanly. While this section uses lists and dictionaries, they contain strings which can be accessed and displayed in a formatted manner.
 
 
 
:'''Perform the Following Steps:'''
 
:#Start the ipython3 shell:<source>
 
ipython3
 
</source>To start, let's use the '''format()''' function on a string, The text '''.format()''' is located at the end of a  defined string. The ''format()'' function can contain arguments or parameters within the parenthesis ( ).<br><br>
 
:#To demonstrate using the ''format()'' function, issue the following:<source>
 
print( 'College is Great'.format() )
 
</source>
 
:#The above example does not actualy do any formatting, next add a string using the format() function arguments<source>
 
print('College is {}'.format('Great'))
 
</source>When the format function reads '''{}''' curly braces, it performs special actions. For example, if format() finds '''{}''' with nothing inside it substitutes the string from it's arguments. These arguments are done by position left to right<br><br>
 
:#To demonstrate, issue the following:<source>
 
print('{} {} {}'.format('a', 'b', 'c'))
 
</source>However, using this method while quick, easy, and clean has a issue. If more curly braces '''{}''' are in the string than in the format() arguments, it will create an '''error'''.<br><br>
 
:#To demonstrate by creating too many braces, issue the following:<source>
 
print('{} {} {} {}'.format('a', 'b', 'c'))
 
</source>For situations like above, if reusing strings more than once is important, '''positional values''' can be placed inside the curly braces.<br><br>
 
:#Issue the following to see what happens:<source>
 
print('{0} {1} {1} {2}'.format('a', 'b', 'c'))
 
print('{2} {2} {1} {0}'.format('a', 'b', 'c'))
 
</source>These positions make formating each string much less prone to errors while also making the string being formatted much more clear.<br><br>
 
:#To improve on formatting further, issue the following to provide the format() function with string variables:<source>
 
course_name = 'Open System Automation'
 
course_code = 'OPS435'
 
print('{0} {1} {0}'.format(course_code, course_name))
 
</source>The format() function by default tries to use values as strings, all values is '''{}''' are displayed as strings unless extra options are given.<br><br>
 
:#Issue the following:<source>
 
course_number = 435            # This is an integer
 
print('This is displaying a string by default: {0}'.format(course_number))
 
</source>Next, let's place a list inside the format() function and access the values, there are two ways to use the list.<br><br>
 
:#Let's demonstrate a range of alternative methods of printing a list by issuing the following:<source>
 
list1 = [1,2,3,4,5]                                            # This is a list of numbers
 
print('{0[0]} {0[1]} {0[2]} {0[3]} {0[4]}'.format(list1))      # Access the values of the list via {position[index]}
 
print('{0} {1} {2} {3} {4}'.format(*list1))                    # Expand the list into multiple positional arguments
 
print('{} {} {} {} {}'.format(*list1))                        # Expand the list into multiple positional arguments
 
print('{0} {1} {2} {3} {4}'.format(1,2,3,4,5))                # Same results as above
 
</source>Let's now place a dictionary inside the format() functions and access the values, again there are a few ways to use the dictionary<br><br>
 
:#Issue the following:<source>
 
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
 
print('{}'.format(dict_york))                                  # Print entire dictionary
 
print('{0}'.format(dict_york))                                # Print entire dictionary using format arguments position
 
print('{0[City]} {0[Country]}'.format(dict_york))              # Print values using position and key {position[key]}
 
</source>With dictionaries however, instead of using positional arguments '''0''' each access to a key, python allows for expansion of keyword arguments.<br><br>
 
:#Let's take a look at the example of a keyword arguments, place the keyword variable name in between '''{}''' and add the keyword argument to the format() function:<source>
 
print('{string1} is {string2} {string2}'.format(string1='College', string2='Great!'))
 
</source>
 
:#Variables may also be passed to these keyword arguments:<source>
 
college = 'Seneca College'
 
print('{string1} is {string2} {string2}'.format(string1=college, string2='Great!'))
 
</source>Now back to dictionaries. Using keyword arguments(sometimes referred to as '''kwargs''' in python). The dictionary can be quickly and easily expanded into these keyword arguments using the syntax '''**dictionary_name'''.<br><br>
 
:#Let's try this below. Pay close attention to the keys inside the dictionary and the values associated with each key:<source>
 
# Define a dictionary:
 
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
 
# Uses the dictionary's keyword arguments:
 
print('{City} {Province} {Country}'.format(**dict_york))                                       
 
# Creates new keyword arguments:
 
print('{City} {Province} {Country}'.format(City='Toronto', Province='ON', Country='Canada'))   
 
</source>
 
 
 
== PART 3 - String Formatting Advanced Features ==
 
 
 
This section shows you how to perform more advanced formatting features via the '''format()''' function. You will learn how to format numbers and aligning strings (text).
 
 
 
:'''Perform the Following Steps'''
 
:#Make certain you are still in your ipython3 shell.<br><br>Let's start advanced formatting for '''numbers'''. Try issuing content below in order to observe the various ways to change the output inside the curly brace '''{}''' while formatting. This formatting change is done by placing a colon inside the curly braces, following by a letter '''{0:f}'''<br><br>
 
:#Issue the following:<source>
 
number1 = 50
 
number2 = -50
 
number3 = 1.50
 
print('{0:f}'.format(number1))          # "0" is the position just like other format() functions
 
print('{0:f}'.format(number2))          # A colon separate the position/index areas from the extra functionality
 
print('{0:f}'.format(number3))          # "f" represents the fixed point number
 
</source>Notice that there are many decimal places after this number. This makes the number look "ugly". We need to further format the number to indicate the number of decimal places (or no decimal places if number is an integer). A fixed point number means that it can control the number of digits that come after the decimal point, try changing the '''.2''' to any other number and experiment.<br><br>
 
:#Issue the following to demonstrate:<source>
 
print('{0:.0f}'.format(number1))        # Show no digits after decimal point
 
print('{0:.2f}'.format(number2))        # Show two digits after decimal point
 
print('{0:.1f}'.format(number3))        # Show one digit after decimal point
 
</source>
 
:#Numbers can be displayed with the '''-''' or '''+''' signs before the digits, this could be important in formatting. Issue the following to demonstrate:<source>
 
print('{0: f}'.format(number1))                    # Show a space where plus sign should be
 
print('{0: f}'.format(number2))                    # Shows negative sign normally
 
print('{0: f}\n{1: f}'.format(number1, number2))    # The space before the f lines up positive and negative numbers
 
</source>
 
:#Placing a '''+''' before the f changes the format so that plus signs show up for positive numbers and negative signs show up for negative numbers. Try issuing the following:<source>
 
print('{0:+f}'.format(number1))                    # Show a space where plus sign should be
 
print('{0:+f}'.format(number2))                    # Shows negative sign normally
 
print('{0:+f}\n{1:+f}'.format(number1, number2))    # The space before the f lines up positive and negative numbers
 
</source>
 
:#Combining fixed point positions can be performed by issuing the following:<source>
 
print('{0:+.2f}'.format(number1))
 
print('{0:+.2f}'.format(number2))
 
print('{0:+.2f}\n{1:+.2f}'.format(number1, number2))
 
</source>In the event that the numbers being shown are all integers and do no require the decimal values, instead of using '''{:f}''',<br> use '''{:d}''' for decimal '''INTEGERS'''.<br><br>
 
:#To demonstrate, issue the following:<source>
 
print('{0:d}'.format(number1))
 
print('{0:d}'.format(number2))
 
print('{0: d}'.format(number1))
 
print('{0: d}'.format(number2))
 
print('{0:+d}'.format(number1))
 
print('{0:+d}'.format(number2))
 
</source>'''NOTE:''' When using '''{:d}''' be careful not to use numbers with a decimal value in them, the following will create a error<br><br>
 
:#Issue the following to see the difference:<source>
 
number3 = 1.50
 
print('{0:d}'.format(number3))
 
</source>Next, let's move on to aligning '''strings''' (text). This is the process of adding padding to the left of our text, the right of our text, or aligning to the centre or our text (i.e. padding both left and right). Through the alignment the text field size, any string can be set to allow it to fit within a column (or columns), and make it easier for the user to read data.<br><br>
 
:#Start by using a string but placeing a number value after the colon '''{0:10}''' by issuing:<source>
 
string1 = 'hello'
 
string2 = 'world'
 
print('{0:10}{1}'.format(string1, string2))      # Make sure string1 is 10 characters aligned to the left
 
print('{0:6}{1}'.format(string1, string2))      # Make sure string1 is 6 characters aligned to the left
 
</source>By default, the format() function aligns to the left, the symbol to do this is '''<''' which is a shortcut for : '''{0:<10}''' when used in the curely braces. Now whenever a different string is placed inside it always aligns to the left 10 characters. This allows for concise code to generate well structured output<br><br>
 
:#To demonstrate this, issue the following:<source>
 
print('{:<10} {:<10} {:<10}\n{:<10} {:<10} {:<10}'.format('abc', 'def', 'ghi', 'jkl123', 'mno123', 'pqr123'))      # Without positional argument numbers
 
print('{0:<10} {1:<10} {2:<10}\n{3:<10} {4:<10} {5:<10}'.format('abc', 'def', 'ghi', 'jkl123', 'mno123', 'pqr123')) # With positional argument numbers
 
</source>
 
:#Next try using right alignment with the '''>''' symbol replacing the left alignment<source>
 
print('{:>10} {:>10} {:>10}\n{:>10} {:>10} {:>10}'.format('abc', 'def', 'ghi', 'jkl123', 'mno123', 'pqr123'))      # Without positional argument numbers
 
print('{0:>10} {1:>10} {2:>10}\n{3:>10} {4:>10} {5:>10}'.format('abc', 'def', 'ghi', 'jkl123', 'mno123', 'pqr123')) # With positional argument numbers
 
</source>
 
:#Finally center alignment with the '''^''' symbol<source>
 
print('{:^10} {:^10} {:^10}\n{:^10} {:^10} {:^10}'.format('abc', 'def', 'ghi', 'jkl123', 'mno123', 'pqr123'))      # Without positional argument numbers
 
print('{0:^10} {1:^10} {2:^10}\n{3:^10} {4:^10} {5:^10}'.format('abc', 'def', 'ghi', 'jkl123', 'mno123', 'pqr123')) # With positional argument numbers
 
</source>
 
:#The alignment character can be changed to any other character that is wanted for the output. By default it's a space, but it could be anything else by adding an additional character '''{:M<10}''' such as '''M''' or '''*''' before the alignment character <source>
 
print('{:*^10} {:*^10} {:*^10}\n{:*^10} {:*^10} {:*^10}'.format('abc', 'def', 'ghi', 'jkl123', 'mno123', 'pqr123'))      # Without positional argument numbers
 
print('{:.^10} {:.^10} {:.^10}\n{:.^10} {:.^10} {:.^10}'.format('abc', 'def', 'ghi', 'jkl123', 'mno123', 'pqr123'))      # Without positional argument numbers
 
</source>
 
:#Make the output look better by creating borders, create this function that displays some data enclosed in borders, try to understand what is happening. This function does not return any value, only prints formatted text<source>
 
def print_with_borders():
 
    print('|{:-^10}|'.format('nums'))
 
    print('|{:^5}{:^5}|'.format(1,2))
 
    print('|{:^5}{:^5}|'.format(3,4))
 
    print('|{}|'.format('-'*10))
 
 
 
# Run the function
 
print_with_borders()
 
</source>
 
'''Create a Script Demonstrating Formatting Strings'''
 
:'''Perform the Following Instructions:'''
 
::#Create the '''~/ops435/lab4/lab4e.py''' script. The purpose of this script is to demonstrate formatting string output from a large data structure.
 
::#Use the following template to get started:<source>
 
#!/usr/bin/env python3
 
# Formatted Strings
 
 
 
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
 
college = 'Seneca College'
 
 
 
def print_college_address():
 
    # Prints out the keys and values from the dictionary
 
    # Formats the output to have a title bar with a title
 
    # EXACT SAME output as the samples
 
 
 
if __name__ == '__main__':
 
    print_college_address(dict_york, college)
 
 
 
</source>
 
:::*The print_college_address() function does NOT return anything
 
:::*The print_college_address() function accept two arguments
 
:::*The first argument is a dictionary
 
:::*The second argument is a string
 
:::*The title printed is center aligned by 40 characters using '-' instead of space for alignment
 
:::*The keys printed are center aligned by 20 characters
 
:::*The values printed are center aligned by 20 characters
 
:::*The output must match the sample output EXACTLY if one character is off it will be wrong
 
:::'''Sample Run 1:'''<source>
 
run lab4e.py
 
|-------------Seneca College-------------|
 
|      Address          70 The Pond Rd  |
 
|      Province              ON        |
 
|    Postal Code            M3J3M6      |
 
|        City              Toronto      |
 
|      Country              Canada      |
 
|----------------------------------------|
 
</source>
 
:::'''Sample Run 2(with import):'''<source>
 
import lab4e
 
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
 
dict_newnham = {'Address': '1750 Finch Ave E', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M2J2X5', 'Province': 'ON'}
 
college = 'Seneca College'
 
 
 
lab4e.print_college_address(dict_york, college)
 
|-------------Seneca College-------------|
 
|      Address          70 The Pond Rd  |
 
|      Province              ON        |
 
|    Postal Code            M3J3M6      |
 
|        City              Toronto      |
 
|      Country              Canada      |
 
|----------------------------------------|
 
 
 
lab4e.print_college_address(dict_newnham, college)
 
|-------------Seneca College-------------|
 
|      Address        1750 Finch Ave E  |
 
|      Province              ON        |
 
|    Postal Code            M2J2X5      |
 
|        City              Toronto      |
 
|      Country              Canada      |
 
|----------------------------------------|
 
</source>
 
::3. Exit the ipython3 shell, download the checking script and check your work. Enter the following commands from the bash shell.<source>
 
cd ~/ops435/lab4/
 
pwd #confirm that you are in the right directory
 
ls CheckLab4.py || wget matrix.senecac.on.ca/~acoatley-willis/CheckLab4.py
 
python3 ./CheckLab4.py -f -v lab4e
 
</source>
 
::4. Before proceeding, make certain that you identify any and all errors in lab4e.py. When the checking script tells you everything is OK before proceeding to the next step.
 
<br><br>
 
  
 
= LAB 4 SIGN-OFF (SHOW INSTRUCTOR) =
 
= LAB 4 SIGN-OFF (SHOW INSTRUCTOR) =
Line 939: Line 539:
 
:'''Have Ready to Show Your Instructor:'''
 
:'''Have Ready to Show Your Instructor:'''
  
::<span style="color:green;font-size:1.5em;">&#x2713;</span> x
+
::<span style="color:green;font-size:1.5em;">&#x2713;</span> Output of: <code>./CheckLab4.py -f -v</code>
::<span style="color:green;font-size:1.5em;">&#x2713;</span> x
+
::<span style="color:green;font-size:1.5em;">&#x2713;</span> Output of: <code>cat lab4a.py lab4b.py lab4c.py lab4d.py</code>
::<span style="color:green;font-size:1.5em;">&#x2713;</span> Lab4 logbook notes completed
+
 
 +
= LAB REVIEW =
  
= Practice For Quizzes, Tests, Midterm &amp; Final Exam =
+
# What is the purpose of a '''tuple'''? How does a tuple differ from a list?
 +
# How do you define elements within a tuple?
 +
# Write Python code to confirm if the string ''''OPS435'''' exists within the tuple called '''courses'''.
 +
# What is the purpose of a '''set'''? How do sets differ from lists or tuples?
 +
# How do you define elements within a set?
 +
# Assuming you have defined two sets called '''set1''' and '''set2'''. Write Python code to:<ol type="a"><li>Return a set containing all values of both sets</li><li>Returns a set containing all values in set1 that are not found in set2</li><li>Return a set containing all values that both sets DO NOT share</li></ol>
 +
# What is the purpose of a dictionary?
 +
# How do you define elements within a dictionary?
 +
# Write Python commands to display for a dictionary called '''my_dictionary''' the dictionary key called '''my_key''' and a dictionary value for that key?
 +
# What is the purpose for the '''range()''', '''len()''', '''append()''', and '''map()''' functions for a dictionary?
 +
# List and briefly explain the following functions (methods) that can be used with strings:<br>'''lower()''' , '''upper()''' , '''swapcase()''' , '''title()''' , '''captilize()''' , '''split()'''
 +
# Assume you issued the following command in your ipython3 shell:<br>'''course_name = 'Programming with Python''''<br>What will be the output for each of the following Python commands?<ol type="a"><li>'''course_name[3:11]'''</li><li>'''course_name[10:]'''</li><li>'''course_name[-1]</li></ol>
  
# x
+
[[Category:OPS435-Python]]
# x
 
# x
 

Latest revision as of 08:26, 21 January 2020

** DO NOT USE - TO BE UPDATED FOR CENTOS 8.0 **

OBJECTIVES

The first investigation in this lab will focus on Data Structures. Each data structure has its own advantages and limitations. This lab will emphasize the most important differences between them.
The second investigation will focus on strings. You have been using and storing strings since our first class, however in this lab we will dive into the more complex nature of string manipulation. Finally, this lab will cover how to use a variety of regular expression functions for searching and input validation.

PYTHON REFERENCE

As you develop your Python scripting skills, you may start to be "overwhelmed" with the volume of information that you have absorbed over these labs. One way to help is to learn to use online references effectively in order to obtain information regarding Python scripting techniques and tools.
Below is a table with links to useful online Python reference sites (by category). You may find these references useful when performing assignments, etc.
Data Structures Lists & List Comprehension Strings Regular Expressions Miscellaneous

INVESTIGATION 1: DATA STRUCTURES

In this investigation, you will learn several data structures commonly used in Python scripting. These tools include lists, tuples, sets, and dictionaries.

PART 1 - Tuples

Many often confuse a tuple with a list (which you learned about in a previous lab). A tuple is a type of list whose values cannot be changed. In fact, nothing in a tuple can be changed after it's created (like adding, removing list elements).
There are many advantages to using tuples when creating Python scripts:
  • Data protection (eg. values are are NOT allowed to change so you won't modify them accidentally)
  • Tuples can be used as keys in data dictionaries (which are NOT allowed to change)
  • Tuples allow for faster access than lists
The term to indicate that a data structure cannot be changed is called immutable (as opposed to "mutable" which means the data structure can be changed).
Perform the Following Steps:
  1. Let's create two tuples in a temporary Python file, so we can learn how to use them and learn how they differ from lists.

    Note: tuples are defined by using parenthesis ( ) as opposed to lists which are defined by using square brackets [ ]
    t1 = ('Prime', 'Ix', 'Secundus', 'Caladan')
    t2 = (1, 2, 3, 4, 5, 6)
  2. Values from a tuple can be retrieved in the same way as a list. For example:
    print(t1[0])
    print(t2[2:4])
  3. You can also check to see whether a value exists inside a tuple or not. To demonstrate try:
    print('Ix' in t1)
    print('Geidi' in t1)
    Let's now see how a tuple differs from a list. We will now create a list and note the difference between them:
    list2 = [ 'uli101', 'ops235', 'ops335', 'ops435', 'ops535', 'ops635' ]
  4. See if you can change the value of your list:
    list2[0]= 'ica100'
    print(list2[0])
    print(list2)
    You should have been successful in changing the value of your list.

  5. Now, try changing the value of your previously-created tuple:
    t2[1] = 10
    Did it work? Once created the tuple values will not be able to change.

    If you would like a tuple with different values than the tuple you currently have, then you must create a new one.

  6. The following creates a new tuple (t3) with a contents from a slice of the t2 tuple. Slicing works the same way for tuples as for lists:
    t3 = t2[2:3]
  7. Also, as with lists, you can use for loops to iterate the values of tuples:
    for item in t1:
        print('item: ' + item)

PART 2 - Sets

So far, you have been exposed to two structures that are used to contain data: lists and tuples. You can modify the values within a list as well as modify the structure of a list (i.e. add and remove elements), whereby you cannot with a tuple.
In this section, you will learn about sets. A set has similar characteristics as a list, but there are two major differing characteristics:
  • Sets are un-ordered
  • Sets cannot contain duplicate values
Since new duplicate entries will be automatically removed when using sets, they are very useful for performing tasks such as comparisons: finding similarities or differences in multiple sets.
  1. Create some sets to work with in a temporary Python file:
    s1 = {'Prime', 'Ix', 'Secundus', 'Caladan'}
    s2 = {1, 2, 3, 4, 5}
    s3 = {4, 5, 6, 7, 8}
    Note: Sets are defined by using braces { } as opposed to tuples which use parenthesis ( ), or lists which use square brackets [ ]

  2. Try to access a set through the index:
    print(s1[0])
    This should have caused an error. You cannot access data inside a set this way because the elements inside are unordered. Instead, you should use the in method to check to see whether a value is contained in the set:
    print('Ix' in s1)
    print('Geidi' in s1)

    Sets can be combined, but it is important to note that any duplicate values (shared among sets) will be deleted.

  3. Print the contents of the sets and note the values that are common:
    print(s2)
    print(s3)
  4. This is how you get a set containing only UNIQUE values (no duplicates) from both sets:
    print(s2 | s3)         # returns a set containing all values from both sets
    print(s2.union(s3))    # same as s2 | s3
    Notice that both methods above have the same result, which one you choose depends purely on your style.

    Instead of combining sets, we can display values that are common to both sets. This is known in mathematical terms as an intersection between the lists:
    print(s2 & s3)             # returns a set containing all values that s2 and s3 share
    print(s2.intersection(s3)) # same as s2 & s3
  5. Sets can also have their values compared against other sets. First find out what items are in s2 but not in s3. This is also called a difference:
    print(s2)
    print(s3)
    print(s2 - s3)             # returns a set containing all values in s2 that are not found in s3
    print(s2.difference(s3))   # same as s2 - s3
  6. In order to see every difference between both sets, you need to find the symmetric difference. This will return a set that shows all numbers that both sets do not share together:
    print(s2 ^ s3)                     # returns a set containing all values that both sets DO NOT share
    print(s2.symmetric_difference(s3)) # same as s2 ^ s3
    Note: the set() function can convert lists into sets, and the list() function can convert sets into lists. The operations in this section can only be applied to sets, so if you need to perform a union, intersection, or difference between lists, you need to convert them to sets first. For example:
    l2 = [1, 2, 3, 4, 5]
    l3 = [4, 5, 6, 7, 8]
    temporary_set = set(l2).intersection(set(l3))
    new_list = list(temporary_set)  # '''set()''' can make lists into sets. '''list()''' can make sets into lists.
    print(new_list)

Create a Python Script Demonstrating Comparing Sets

Perform the Following Instructions
  1. Create the ~/ops435/lab4/lab4a.py script. The purpose of this script will be to demonstrate the different way of comparing sets. There will be three functions, each returning a different set comparison.
  2. Use the following template to get started:
    #!/usr/bin/env python3
    
    def join_sets(s1, s2):
        # join_sets will return a set that contains every value from both s1 and s2
    
    def match_sets(s1, s2):
        # match_sets will return a set that contains all values found in both s1 and s2
    
    def diff_sets(s1, s2):
        # diff_sets will return a set that contains all different values which are not shared between the sets
    
    if __name__ == '__main__':
        set1 = set(range(1,10))
        set2 = set(range(5,15))
        print('set1: ', set1)
        print('set2: ', set2)
        print('join: ', join_sets(set1, set2))
        print('match: ', match_sets(set1, set2))
        print('diff: ', diff_sets(set1, set2))
  • The join_sets() function should return a set that contains all values from both sets
  • The match_sets() function should return a set that contains all values found in both sets
  • The diff_sets() function should return a set that contains all values which are not shared between both sets
  • All three functions should accept two arguments both are sets
  • The script should show the exact output as the samples
  • The script should contain no errors
Sample Run 1:
./lab4a.py
set1:  {1, 2, 3, 4, 5, 6, 7, 8, 9}
set2:  {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
join:  {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
match:  {8, 9, 5, 6, 7}
diff:  {1, 2, 3, 4, 10, 11, 12, 13, 14}
Sample Run 2 (with import):
import lab4a
set1 = {1,2,3,4,5}
set2 = {2,1,0,-1,-2}
print(lab4a.join_sets(set1,set2))
# Will output {-2, -1, 0, 1, 2, 3, 4, 5}
print(lab4a.match_sets(set1,set2))
# Will output {1, 2}
print(lab4a.diff_sets(set1,set2))
# Will output {-2, -1, 0, 3, 4, 5}
  1. Download the checking script and check your work. Enter the following commands from the bash shell:
    cd ~/ops435/lab4/
    pwd #confirm that you are in the right directory
    ls CheckLab4.py || wget https://raw.githubusercontent.com/Seneca-CDOT/ops435/master/LabCheckScripts/CheckLab4.py
    python3 ./CheckLab4.py -f -v lab4a
  2. Before proceeding, make certain that you identify all errors in lab4a.py. When the checking script tells you everything is OK - proceed to the next step.

Create a Python Script Demonstrating Comparing Lists

Perform the Following Instructions
  1. Create the ~/ops435/lab4/lab4b.py script. The purpose of this script will be to improve the previous script to perform the same joins, matches, and diffs, but this time on lists.
  2. Use the following as a template:
    #!/usr/bin/env python3
    
    def join_lists(l1, l2):
        # join_lists will return a list that contains every value from both l1 and l2
    
    def match_lists(l1, l2):
        # match_lists will return a list that contains all values found in both l1 and l2
    
    def diff_lists(l1, l2):
        # diff_lists will return a list that contains all different values, which are not shared between the lists
    
    if __name__ == '__main__':
        list1 = list(range(1,10))
        list2 = list(range(5,15))
        print('list1: ', list1)
        print('list2: ', list2)
        print('join: ', join_lists(list1, list2))
        print('match: ', match_lists(list1, list2))
        print('diff: ', diff_lists(list1, list2))
  • The match_lists() function should return a list that contains all values found in both lists
  • The diff_lists() function should return a list that contains all values which are not shared between both lists
  • The join_lists() function should return a list that contains all values from both lists
  • All three functions should accept two arguments both are lists
  • The script should show the exact output as the samples
  • The script should contain no errors
Sample Run 1:
./lab4b.py
list1:  [1, 2, 3, 4, 5, 6, 7, 8, 9]
list2:  [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
join:  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
match:  [5, 6, 7, 8, 9]
diff:  [1, 2, 3, 4, 10, 11, 12, 13, 14]
Sample Run 2 (with import) under interactive python shell:
import lab4b
list1 = [1,2,3,4,5]
list2 = [2,1,0,-1,-2]
print(lab4b.join_lists(list1,list2)))
# Will output [0, 1, 2, 3, 4, 5, -2, -1]
print(lab4b.match_lists(list1,list2))                                                                                                                 
# Will output [1, 2]
print(lab4b.diff_lists(list1,list2))                                                                                                                  
# Will output [0, 3, 4, 5, -2, -1]
3. Download the checking script and check your work. Enter the following commands from the bash shell.
cd ~/ops435/lab4/
pwd #confirm that you are in the right directory
ls CheckLab4.py || wget matrix.senecac.on.ca/~acoatley-willis/CheckLab4.py
python3 ./CheckLab4.py -f -v lab4b
4. Before proceeding, make certain that you identify all errors in lab4b.py. When the checking script tells you everything is OK - proceed to the next step.

PART 3 - Dictionaries

In Python, a dictionary is a set of key-value pairs. Dictionaries are unordered, like sets, however any value can be retrieved from a dictionary if you know the key. This section will go over how to create, access, and change dictionaries, giving you a new powerful tool to store and manipulate data.
Perform the Following Steps:
  1. Let's begin by creating a new dictionary in a temporary Python file:
    dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Postal Code': 'M3J3M6'}
    You should note that the syntax to define a dictionary is similar to defining sets (i.e. using {}), but unlike sets dictionaries use key:value pairs within the dictionary, each key:value pair is separated by commas.
  2. All the values in a dictionary can be retrieved by using the dictionary.values() function. This particular function provides a list containing all values:
    print(dict_york.values())
    All keys to access the key:pair values within a dictionary can be retrieved using the dictionary.keys() function:
    dict_york.keys()
    We can retrieve individual values from a dictionary by providing the key associated with the value:
    print(dict_york['Address'])
    print(dict_york['Postal Code'])
  3. Dictionary keys can be any immutable values (i.e. not permitted for value to be changed). Types of values include: strings, numbers, and tuples.
  4. Try adding a new key and value to the dictionary:
    dict_york['Country'] = 'Canada'
    print(dict_york)
    print(dict_york.values())
    print(dict_york.keys())
  5. Let's change the province value to BC:
    dict_york['Province'] = 'BC'
    print(dict_york)
    print(dict_york.values())
    print(dict_york.keys())
    WARNING: Dictionary keys must be unique. Attempting to add a key that already exists in the dictionary will overwrite the existing value for that key! For example:
    dict_york['Province'] = 'ON'
    print(dict_york)
    print(dict_york.values())
    print(dict_york.keys())
    You should notice that value for the 'Province' key has been changed back to 'ON'.

    The lists that contain the values and keys of the dictionary are not real python lists - they are "views of the dictionary" and therefore are immutable. You could change these views into usable lists by using the list() function:
    list_of_keys = list(dict_york.keys())
    print(list_of_keys[0])
  6. Lists can be used with for loops:
    list_of_keys = list(dict_york.keys())
    for key in list_of_keys:
        print(key)
    for value in dict_york.values():
        print(value)

Create a Python Script for Managing Dictionaries

Perform the Following Instructions
  1. Create the ~/ops435/lab4/lab4c.py script. The purpose of this script will be to create dictionaries, extract data from dictionaries, and to make comparisons between dictionaries.
  2. Use the following as a template:
    #!/usr/bin/env python3
    
    # Dictionaries
    dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
    dict_newnham = {'Address': '1750 Finch Ave E', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M2J2X5', 'Province': 'ON'}
    # Lists
    list_keys = ['Address', 'City', 'Country', 'Postal Code', 'Province']
    list_values = ['70 The Pond Rd', 'Toronto', 'Canada', 'M3J3M6', 'ON']
    
    def create_dictionary(keys, values):
        # Place code here - refer to function specifics in section below
    
    def shared_values(dict1, dict2):
        # Place code here - refer to function specifics in section below
    
    
    if __name__ == '__main__':
        york = create_dictionary(list_keys, list_values)
        print('York: ', york)
        common = shared_values(dict_york, dict_newnham)
        print('Shared Values', common)
  • The script should contain two functions:
create_dictionary()
  1. accepts two lists as arguments keys and values, combines these lists together to create a dictionary
    (Tip: use a while loop to access elements in both the keys and values lists at the same time)
  2. returns a dictionary that has the keys and associated values from the lists
shared_values()
  1. accepts two dictionaries as arguments and finds all values that are shared between the two dictionaries
    (Tip: generate sets containing only values for each dictionary, then use a function mentioned in a previous section to store the values that are common to both lists)
  2. returns a set containing ONLY values found in BOTH dictionaries
  • make sure the functions have the correct number of arguments required
  • The script should show the exact output as the samples
  • The script should contain no errors
Sample Run 1:
./lab4c.py
York:  {'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Address': '70 The Pond Rd', 'Province': 'ON', 'City': 'Toronto'}
Shared Values {'Canada', 'ON', 'Toronto'}
Sample Run 2 (with import):
import lab4c
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
dict_newnham = {'Address': '1750 Finch Ave E', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M2J2X5', 'Province': 'ON'}
list_keys = ['Address', 'City', 'Country', 'Postal Code', 'Province']
list_values = ['70 The Pond Rd', 'Toronto', 'Canada', 'M3J3M6', 'ON']

york = lab4c.create_dictionary(list_keys, list_values)

print(york)
# Will print: {'Address': '70 The Pond Rd',
               'City': 'Toronto',
               'Country': 'Canada',
               'Postal Code': 'M3J3M6',
               'Province': 'ON'}

common = lab4c.shared_values(dict_york, dict_newnham)

print(common)
# Will print: {'Canada', 'ON', 'Toronto'}
3. Download the checking script and check your work. Enter the following commands from the bash shell.
cd ~/ops435/lab4/
pwd #confirm that you are in the right directory
ls CheckLab4.py || wget https://raw.githubusercontent.com/Seneca-CDOT/ops435/master/LabCheckScripts/CheckLab4.py
python3 ./CheckLab4.py -f -v lab4c
4. Before proceeding, make certain that you identify all errors in lab4c.py. When the checking script tells you everything is OK proceed to the next step.

INVESTIGATION 2: STRINGS

Strings are basically a list of characters (bits of text). This section will investigate strings in more detail such as cutting strings into sub-strings, joining strings, formatting strings, searching through strings, and matching strings against patterns.

Strings are immutable data objects - this means that once a string is created, it cannot be modified. In order to make a change inside a string, you would first make a copy of the part of the string (i.e. sub-string) for manipulation.

PART 1 - Strings and Substrings

This first part will explain basic concepts of using strings, printing strings, and manipulating sub-strings.
Perform the Following Steps:
  1. Create some strings in a temporary Python file:
    course_name = 'Open System Automation'
    course_code = 'OPS435'
    course_number = 435
    Strings can contain any characters inside them, whether they are letters, numbers, or symbols.
  2. Strings can also be concatenated (i.e. "combined together") by using the + sign, just make sure string are only concatenating strings with strings (no lists, no numbers, no dictionaries, etc.):
    print(course_name)
    print(course_code)
    print(str(course_number))
    print(course_name + ' ' + course_code + ' ' + str(course_number))
    When using the print() function, you can display special characters. One such special character is the is the newline character (denoted by the symbol: \n). This allows you to separate content between new lines or empty lines:
    print('Line 1\nLine 2\nLine 3\n')
  3. Strings have many built-in functions that we can use to manipulate text. Here's a list.
  4. Lets try out several different functions:
    print(course_name.lower())         # Returns a string in lower-case letters
    print(course_name.upper())         # Returns a string in upper-case letters
    print(course_name.swapcase())      # Returns a string with upper-case and lower-case letters swapped
    print(course_name.title())         # Returns a string with upper-case first letter of each word, lowercase for remaining text
    print(course_name.capitalize())    # Returns a string with upper-case first letter only, lowercase for remaining text
  5. These values can be saved inside new strings and then reused:
    lower_name = course_name.lower()    # Save returned string lower-case string inside new string variable
    print(lower_name)
  6. If a string contains many values separated by a single character, such as a space, the string can be split on those values and create a list of values
    lower_name.split(' ')       # Provide the split() function with a character to split on
    The above example will return a list of strings, which we can access just like all of lists.

  7. Let's practice more string manipulation:
    list_of_strings = lower_name.split(' ')     # Split string on spaces and store the list in a variable
    print(list_of_strings)                      # Display list
    print(list_of_strings[0])                   # Display first item in list
    Since lists are actually a list of strings, you should be able to use any function that works with a string on a list:
    list_of_strings[0].upper()           # Use the function after the index to affect a single string within a list
    first_word = list_of_strings[0]
    print(first_word)
    The index that is used to access items within a list, can also be used to access characters within a string. For practice, let's create a new string, and start accessing the strings index:
    course_name = 'Open System Automation'
    course_code = 'OPS435'
    course_number = 435
    print(course_code[0])                          # Print the first character in course_code
    print(course_code[2])                          # Print the third character in course_code
    print(course_code[-1])                         # Print the last character in course_code
    print(str(course_number)[0])                   # Turn the integer into a string, return first character in that string, and print it
    print(course_code[0] + course_code[1] + course_code[2])
  8. You can use a technique that uses index numbers of a string to cut-out or "parse" smaller portions of text within a string. This term is referred to as a substring. We can use this to create a new string or display only a small portion of it:
    print(course_name[0:4])                 # Print the first four characters (values of index numbers 0,1,2, and 3) 
    first_word = course_name[0:4]           # Save this substring for later use
    print(course_code[0:3])                 # Print the first three characters (values of index numbers 0,1,and 2)
  9. The index allows a few extra functions using the same parsing technique:
    course_name = 'Open System Automation'
    print(course_name[12:])                        # Print the substring '12' index until end of string
    print(course_name[5:])                         # Print the substring '5' index until end of string
    print(course_name[-1])                         # Print the last character
    With negative indices, -1 would represent the last character, -2 index would represent the second last character, etc.:
    course_name = 'Open System Automation'
    print(course_name[-1])
    print(course_name[-2])
  10. Practice some of the skills that you have learned in this section:
    course_name = 'Open System Automation'
    print(course_name[-10:])                            # Return the last ten characters
    print(course_name[-10:-6])                          # Try and figure out what this is returning 
    print(course_name[0:4] + course_name[-10:-6])       # Combine substrings together
    substring = course_name[0:4] + course_name[-10:-6]  # Save the combined substring as a new string for later
    print(substring)
  11. The real power found in substrings goes beyond just manually writing index values and getting back words. The next part of this investigation will cover how to search through a string for a specific word, letter, number, and return the index to that search result.

Create a Python Script Demostrating Substrings

Perform the Following Instructions
  1. Create the ~/ops435/lab4/lab4d.py script. The purpose of this script is to demonstrate creating and manipulating strings. There will be four functions each will return a single string.
  2. Use the following template to get started:
    #!/usr/bin/env python3
    # Strings 1
    
    str1 = 'Hello World!!'
    str2 = 'Seneca College'
    
    num1 = 1500
    num2 = 1.50
    
    def first_five():
        # Place code here - refer to function specifics in section below
    
    def last_seven():
        # Place code here - refer to function specifics in section below
    
    def middle_number():
        # Place code here - refer to function specifics in section below
    
    def first_three_last_three():
        # Place code here - refer to function specifics in section below
    
    
    if __name__ == '__main__':
        print(first_five(str1))
        print(first_five(str2))
        print(last_seven(str1))
        print(last_seven(str2))
        print(middle_number(num1))
        print(middle_number(num2))
        print(first_three_last_three(str1, str2))
        print(first_three_last_three(str2, str1))
  • The script should contain four functions (use your own argument names):
first_five():
  1. Accepts a single string argument
  2. Returns a string that contains the first five characters of the argument given
last_seven():
  1. Accepts a single string argument
  2. Returns a string that contains the last seven characters of the argument given
middle_number():
  1. Accepts a integer as a argument
  2. Returns a string containing the second and third characters in the number
first_three_last_three():
  1. Accepts two string arguments
  2. Returns a single string that starts with the first three characters of argument1 and ends with the last three characters of argument2
  • Example: first_three_last_three('abcdefg', '1234567') returns single string 'abc567'
Sample Run 1
./lab4d.py 
Hello
Senec
World!!
College
50
.5
Helege
Send!!
Sample Run 2 (with import)
import lab4d

str1 = 'Hello World!!'
str2 = 'Seneca College'
num1 = 1500
num2 = 1.50

print(lab4d.first_five(str1))
# Will output 'Hello'
print(lab4d.first_five(str2))
# Will output 'Senec'
print(lab4d.last_seven(str1))
# Will output 'World!!'
print(lab4d.last_seven(str2))
# Will output 'College'
print(lab4d.middle_number(num1))
# Will output '50'
print(lab4d.middle_number(num2))
# Will output '.5'
print(lab4d.first_three_last_three(str1, str2))
# Will output 'Helege'
print(lab4d.first_three_last_three(str2, str1))
# Will output 'Send!!'
3. Download the checking script and check your work. Enter the following commands from the bash shell.
cd ~/ops435/lab4/
pwd #confirm that you are in the right directory
ls CheckLab4.py || wget https://raw.githubusercontent.com/Seneca-CDOT/ops435/master/LabCheckScripts/CheckLab4.py
python3 ./CheckLab4.py -f -v lab4d
4. Before proceeding, make certain that you identify all errors in lab4d.py. When the checking script tells you everything is OK - proceed to the next step.

LAB 4 SIGN-OFF (SHOW INSTRUCTOR)

Students should be prepared with all required commands (system information) displayed in a terminal (or multiple terminals) prior to calling the instructor for signoff.


Have Ready to Show Your Instructor:
Output of: ./CheckLab4.py -f -v
Output of: cat lab4a.py lab4b.py lab4c.py lab4d.py

LAB REVIEW

  1. What is the purpose of a tuple? How does a tuple differ from a list?
  2. How do you define elements within a tuple?
  3. Write Python code to confirm if the string 'OPS435' exists within the tuple called courses.
  4. What is the purpose of a set? How do sets differ from lists or tuples?
  5. How do you define elements within a set?
  6. Assuming you have defined two sets called set1 and set2. Write Python code to:
    1. Return a set containing all values of both sets
    2. Returns a set containing all values in set1 that are not found in set2
    3. Return a set containing all values that both sets DO NOT share
  7. What is the purpose of a dictionary?
  8. How do you define elements within a dictionary?
  9. Write Python commands to display for a dictionary called my_dictionary the dictionary key called my_key and a dictionary value for that key?
  10. What is the purpose for the range(), len(), append(), and map() functions for a dictionary?
  11. List and briefly explain the following functions (methods) that can be used with strings:
    lower() , upper() , swapcase() , title() , captilize() , split()
  12. Assume you issued the following command in your ipython3 shell:
    course_name = 'Programming with Python'
    What will be the output for each of the following Python commands?
    1. course_name[3:11]
    2. course_name[10:]
    3. course_name[-1]