Code Projects & Wrap Up#
Q&A
Q: Could you give more examples on code style? I would be very helpful.
A: Yup - we’ll do a few more today!
Q: How is code style tested on the final?
A: We’ll use a linter, with a permissive threshold (discussed today)
Q: (in reference to improved code style) im not sure what is the difference btw this and the normal code? can you explain more pls
A: Functionally, for the computer, there’s nothing different. But, when we improve code style, it makes the code easier to read/understand by the humans.
Q: Will we have to remember any specific NumPy or Pandas methods on the Final?
A: No - all methods will be explained what they’re function is. You’ll need to know how to use them once you know what they do.
Course Announcements
Due this week:
CL9 (due Fri; optional, for 2 pts EC…but you should do it to get testing practice)
E1 or E2 retake (optional)
Final Exam (6/7-6/13)
Do the practice final exam
Post-course assessement (due 6/13; required; will be available Friday)
Notes:
Please complete your SETs - opportunity for EC
If >= 70% of the class completes their SETs for the course -> +0.5% (currently: 22%)
If any one staff member gets 7% of the class (43 people) to give them evals -> +0.5%
Office Hours end this Friday (no office hours during finals week; I will monitor Ed/email)
I do not round grades up
The Plan#
Code Projects
Projects you can now do…
Atbash encryption project example
Refactoring Code
Where to after COGS 18?
Some examples of projects you could try after COGS 18#
Chatbot: start and end a chat
Data Analysis: read a dataset in, make a basic plot
Car Inventory: object with method that adds a car to the Inventory
Artificial Agents: simple bot moves around randomly
Project Organization#
Notebooks: good for interactive development
For when seeing the inputs and outputs of code running needs to be seen start to finish
file ends in
.ipynb
Modules: for storing mature Python code, that you can import
you don’t use the functions in there, just define them
file ends in
.py
Scripts: a Python file for executing a particular task
this takes an input and does something start to finish
file ends in
.py
Project Workflow#
Typical project workflow:
Develop plan and write tests
Develop code interactively in a Jupyter notebook/text editor
As functions & classes become mature, move them to Python files that you then
import
As you do so, go back through them to check for code style, add documentation, and run your code tests
At the end of a project, (maybe) write a standalone script that runs the project
Project Notes#
Design and write tests
Write some code
Test to make sure it works
Check code style (naming, spacing, etc.)
Add documentation
Move to module (if necessary)
Run all tests
Project Design#
Idea: atbash encryption: return the capitalized, reverse alphabetical letter for each character in the input string
Design:
atbash_encrypt()
: take input string and retrun atbash encrypted stringinputs:
input_string
returns:
atbash_string
atbash_decrypt()
: take encrypted string and decrypt using atbashinputs:
atbash_string
returns:
decrypted_string
atbash_wrapper()
: does either of the above, as specified with input parameterinputs:
input_string
,method
(either ‘encrypt’ or ‘decrypt’, default: ‘encrypt’)returns
output_string
Adding Unit Tests#
consider imports at the top
tests to check each function
check is callable/output is correct type
check specific output is correct (consider capitalization)
import unittest
from atbash import atbash_encrypt, atbash_decrypt, atbash_wrapper
class TestEncrypt(unittest.TestCase):
def test_exist(self):
self.assertTrue(callable(atbash_encrypt))
def test_type(self):
self.assertIsInstance(atbash_encrypt('hello'), str)
def test_output(self):
self.assertEqual('SVOOL', atbash_encrypt('HELLO'))
self.assertEqual('SVOOL', atbash_encrypt('hello'))
class TestDecrypt(unittest.TestCase):
def test_exist(self):
self.assertTrue(callable(atbash_decrypt))
def test_type(self):
self.assertIsInstance(atbash_decrypt('hello'), str)
def test_output(self):
self.assertEqual('HELLO', atbash_decrypt('SVOOL'))
self.assertEqual('HELLO', atbash_decrypt('svool'))
class TestWrapper(unittest.TestCase):
def test_exist(self):
self.assertTrue(callable(atbash_wrapper))
def test_type(self):
self.assertIsInstance(atbash_wrapper('hello', method='encrypt'), str)
def test_output_encrypt(self):
self.assertEqual('SVOOL', atbash_wrapper('hello', method='encrypt'))
self.assertEqual('SVOOL', atbash_wrapper('HELLO', method='encrypt'))
def test_output_decrypt(self):
self.assertEqual('HELLO', atbash_wrapper('SVOOL', method='decrypt'))
self.assertEqual('HELLO', atbash_wrapper('svool', method='decrypt'))
def test_output_other(self):
self.assertEqual("method should be either 'decrypt' or 'encrypt'", atbash_wrapper('svool', method='blargh'))
Writing Code#
atbash_encrypt
#
def atbash_encrypt(input_string):
alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
reverse_alpha = 'ZYXWVUTSRQPONMLKJIHGFEDCBA'
atbash_string = ''
for char in input_string:
char = char.upper()
if char in alpha:
position = alpha.find(char)
atbash_string += reverse_alpha[position]
else:
atbash_string = None
break
return atbash_string
# smoke test
atbash_encrypt('Hello')
'SVOOL'
Moving to a module…#
consider imports at the top
Note on imports
: If you want to be able to use modules (imports) within a module/script, be sure to import it at the top. This applies to test files as well.
# Run tests
import unittest
suite = unittest.TestLoader().discover('.', pattern='test_atbash.py')
unittest.TextTestRunner(verbosity=2).run(suite)
test_exist (test_atbash.TestEncrypt.test_exist) ... ok
test_output (test_atbash.TestEncrypt.test_output) ... ok
test_type (test_atbash.TestEncrypt.test_type) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
<unittest.runner.TextTestResult run=3 errors=0 failures=0>
atbash_decrypt
#
# reminder: consider code style!
def atbash_decrypt(atbash_string):
ALPHA='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
REVERSEALPHA='ZYXWVUTSRQPONMLKJIHGFEDCBA'
atbash_string=atbash_string.upper()
decrypted_string=''
for l in atbash_string:
if l in REVERSEALPHA:
letterindex = REVERSEALPHA.find(l)
decrypted_string = decrypted_string + ALPHA[letterindex]
else:
decrypted_string=decrypted_string + l
return decrypted_string
# smoke test
atbash_decrypt('SVOOL')
'HELLO'
# Run tests
import unittest
suite = unittest.TestLoader().discover('.', pattern='test_atbash.py')
unittest.TextTestRunner(verbosity=2).run(suite)
test_exist (test_atbash.TestDecrypt.test_exist) ... ok
test_output (test_atbash.TestDecrypt.test_output) ... ok
test_type (test_atbash.TestDecrypt.test_type) ... ok
test_exist (test_atbash.TestEncrypt.test_exist) ... ok
test_output (test_atbash.TestEncrypt.test_output) ... ok
test_type (test_atbash.TestEncrypt.test_type) ... ok
----------------------------------------------------------------------
Ran 6 tests in 0.003s
OK
<unittest.runner.TextTestResult run=6 errors=0 failures=0>
atbash_wrapper
#
def atbash_wrapper(input_string, method='encrypt'):
if method == 'encrypt':
output_string = atbash_encrypt(input_string)
elif method == 'decrypt':
output_string = atbash_decrypt(input_string)
else:
output_string = "method should be either 'decrypt' or 'encrypt'"
return output_string
# smoke test
atbash_wrapper('hello')
'SVOOL'
import unittest
# Run tests
suite = unittest.TestLoader().discover('.', pattern='test_atbash.py')
unittest.TextTestRunner(verbosity=2).run(suite)
test_exist (test_atbash.TestDecrypt.test_exist) ... ok
test_output (test_atbash.TestDecrypt.test_output) ... ok
test_type (test_atbash.TestDecrypt.test_type) ... ok
test_exist (test_atbash.TestEncrypt.test_exist) ... ok
test_output (test_atbash.TestEncrypt.test_output) ... ok
test_type (test_atbash.TestEncrypt.test_type) ... ok
test_exist (test_atbash.TestWrapper.test_exist) ... ok
test_output_decrypt (test_atbash.TestWrapper.test_output_decrypt) ... ok
test_output_encrypt (test_atbash.TestWrapper.test_output_encrypt) ... ok
test_output_other (test_atbash.TestWrapper.test_output_other) ... ok
test_type (test_atbash.TestWrapper.test_type) ... ok
----------------------------------------------------------------------
Ran 11 tests in 0.006s
OK
<unittest.runner.TextTestResult run=11 errors=0 failures=0>
Documentation#
Let’s add:
numpy-style docstrings
code comments
Putting it all together#
from atbash import atbash_wrapper
atbash_wrapper('hello')
'SVOOL'
atbash_wrapper('svool', method='decrypt')
'HELLO'
atbash_wrapper('hello', method='blargh')
"method should be either 'decrypt' or 'encrypt'"
Refactoring#
Think of this as restructuring and final edits on your essay.
Nesting Functions - If you have a whole bunch of functions, if statements, and for/while loops together within a single function, you probably want (need?) to refactor.
Clean functions accomplish a single task!
DRY: Don’t Repeat Yourself
Refactoring Example: Chatbot#
import random
def have_a_chat():
"""Main function to run our chatbot."""
chat = True
while chat:
# Get a message from the user
msg = input('INPUT :\t')
out_msg = None
# Check if the input is a question
input_string = msg
if '?' in input_string:
question = True
else:
question = False
# Check for an end msg
if 'quit' in input_string:
out_msg = 'Bye!'
chat = False
# If we don't have an output yet, but the input was a question,
# return msg related to it being a question
if not out_msg and question:
out_msg = "I'm too shy to answer questions. What do you want to talk about?"
# Catch-all to say something if msg not caught & processed so far
if not out_msg:
out_msg = random.choice(['Good.', 'Okay', 'Huh?', 'Yeah!', 'Thanks!'])
print('OUTPUT:', out_msg)
have_a_chat()
OUTPUT: Okay
OUTPUT: I'm too shy to answer questions. What do you want to talk about?
OUTPUT: Okay
OUTPUT: Bye!
Refactored Example: Chatbot#
What this function does:
takes an input
checks if input is a question
checks if input is supposed to end the chat
return appropriate response if question, end chat, or other
That’s four different things! Functions should do a single thing…
def get_input():
"""ask user for an input message"""
msg = input('INPUT :\t')
out_msg = None
return msg, out_msg
def is_question(input_string):
"""determine if input from user is a question"""
if '?' in input_string:
output = True
else:
output = False
return output
def end_chat(input_list):
"""identify if user says 'quit' in input and end chat"""
if 'quit' in input_list:
output = 'Bye'
chat = False
else:
output = None
chat = True
return output, chat
def return_message(out_msg, question):
"""generic responses for the chatbot to return"""
# If we don't have an output yet, but the input was a question,
# return msg related to it being a question
if not out_msg and question:
out_msg = "I'm too shy to answer questions. What do you want to talk about?"
# Catch-all to say something if msg not caught & processed so far
if not out_msg:
out_msg = random.choice(['Good.', 'Okay', 'Huh?', 'Yeah!', 'Thanks!'])
return out_msg
def have_a_chat():
"""Main function to run our chatbot."""
chat = True
while chat:
# Get input message from the user
msg, out_msg = get_input()
# Check if the input is a question
question = is_question(msg)
# Check for an end msg
out_msg, chat = end_chat(msg)
# specify what to return
out_msg = return_message(out_msg = out_msg, question = question)
print('OUTPUT:', out_msg)
have_a_chat()
OUTPUT: Thanks!
OUTPUT: I'm too shy to answer questions. What do you want to talk about?
OUTPUT: Thanks!
OUTPUT: I'm too shy to answer questions. What do you want to talk about?
OUTPUT: Thanks!
OUTPUT: Bye
The Goal#
To teach you a skill - of how to do things with Python.
You’ve been more formally trained than many people out in the world programming.
Where We’ve Been:#
Python & Jupyter
Variables
Operators
Conditionals
Functions
Lists, Tuples & Dictionaries
Loops
Objects & Classes
Command Line
Scientific Computing
Documentation, Code Style, Code Testing
Activity: Wrap-up#
Please complete the following Google Form: https://forms.gle/xdUjB27ywgG5bn4t7
How to Continue with Coding#
Write Code
Read Code
Learn and follow standard procedures
Do code reviews
Interact with the community
Build a code portfolio
Where do you go from here? (things)#
if want_more_data_science:
go to COGS 9
if you want to do more_data_science:
…and Python: take COGS 108
…and R: take COGS 137
if interested_in_research:
look for labs, tell them you can code
if you want_something_else:
go do it!
Acknowledgments#
Thank you to the TAs & IAs for their tireless work on this class.
Thank you students for you time, effort and patience.