In-Class Coding Lab: Functions

The goals of this lab are to help you to understand:

  • How to use Python's built-in functions in the standard library.
  • How to write user-defined functions
  • How to use other people's code.
  • The benefits of user-defined functions to code reuse and simplicity.
  • How to create a program to use functions to solve a complex idea

We will demonstrate these through the following example:

The Credit Card Problem

If you're going to do commerce on the web, you're going to support credit cards. But how do you know if a given number is valid? And how do you know which network issued the card?

Example: Is 5300023581452982 a valid credit card number?Is it? Visa? MasterCard, Discover? or American Express?

While eventually the card number is validated when you attempt to post a transaction, there's a lot of reasons why you might want to know its valid before the transaction takes place. The most common being just trying to catch an honest key-entry mistake made by your site visitor.

So there are two things we'd like to figure out, for any "potential" card number:

  • Who is the issuing network? Visa, MasterCard, Discover or American Express.
  • IS the number potentially valid (as opposed to a made up series of digits)?

What does this have to do with functions?

If we get this code to work, it seems like it might be useful to re-use it in several other programs we may write in the future. We can do this by writing the code as a function. Think of a function as an independent program its own inputs and output. The program is defined under a name so that we can use it simply by calling its name.

Example: n = int("50") the function int() takes the string "50" as input and converts it to an int value 50 which is then stored in the value n.

When you create these credit card functions, we might want to re-use them by placing them in a Module which is a file with a collection of functions in it. Furthermore we can take a group of related modules and place them together in a Python Package. You install packages on your computer with the pip command.

Built-In Functions

Let's start by checking out the built-in functions in Python's math library. We use the dir() function to list the names of the math library:


In [ ]:
import math

dir(math)

If you look through the output, you'll see a factorial name. Let's see if it's a function we can use:


In [ ]:
help(math.factorial)

It says it's a built-in function, and requies an integer value (which it referrs to as x, but that value is arbitrary) as an argument. Let's call the function and see if it works:


In [ ]:
math.factorial(5) #this is an example of "calling" the function with input 5. The output should be 120

In [ ]:
math.factorial(0) # here we call the same function with input 0. The output should be 1.

In [ ]:
## Call the factorial function with an input argument of 4. What is the output?
#TODO write code here.

Using functions to print things awesome in Juypter

Until this point we've used the boring print() function for our output. Let's do better. In the IPython.display module there are two functions display() and HTML(). The display() function outputs a Python object to the Jupyter notebook. The HTML() function creates a Python object from HTML Markup as a string.

For example this prints Hello in Heading 1.


In [ ]:
from IPython.display import display, HTML

print("Exciting:")
display(HTML("<h1>Hello</h1>"))
print("Boring:")
print("Hello")

Let's keep the example going by writing two of our own functions to print a title and print text as normal, respectively.

Execute this code:


In [ ]:
def print_title(text):
    '''
    This prints text to IPython.display as H1
    '''
    return display(HTML("<H1>" + text + "</H1>"))

def print_normal(text):
    '''
    this prints text to IPython.display as normal text
    '''
    return display(HTML(text))

Now let's use these two functions in a familiar program!


In [ ]:
print_title("Area of a Rectangle")
length = float(input("Enter length: "))
width = float(input("Enter width: "))
area = length * width
print_normal("The area is %.2f" % area)

Using Other People's Code

Now that we know a bit about Packages, Modules, and Functions let me expand your horizons a bit. There's a whole world of Python code out there that you can use, and it's what makes Python the powerful and popular programming language that it is today. All you need to do to use it is read!

For example. Let's say I want to print some emojis in Python. I might search the Python Package Index https://pypi.org/ for some modules to try.

For example this one: https://pypi.org/project/emoji/

Let's take it for a spin!

Installing with pip

First we need to install the package with the pip utility. This runs from the command line, so to execute pip within our notebook we use the bang ! operator.

This downloads the package and installs it into your Python environment, so that you can import it.


In [ ]:
!pip install emoji

Once the package is installed we can use it. Learning how to use it is just a matter of reading the documentation and trying things out. There are no short-cuts here! For example:


In [ ]:
# TODO: Run this
import emoji
print(emoji.emojize('Python is :thumbs_up:'))
print(emoji.emojize('But I thought this :lab_coat: was supposed to be about :credit_card: ??'))

Now you try it

Write a python program to print the bacon and ice cream emojis


In [ ]:
## TODO: Write your code here

Let's get back to credit cards....

Now that we know a bit about Packages, Modules, and Functions let's attempt to write our first function. Let's tackle the easier of our two credit card related problems:

  • Who is the issuing network? Visa, MasterCard, Discover or American Express.

This problem can be solved by looking at the first digit of the card number:

  • "4" ==> "Visa"
  • "5" ==> "MasterCard"
  • "6" ==> "Discover"
  • "3" ==> "American Express"

So for card number 5300023581452982 the issuer is "MasterCard".

It should be easy to write a program to solve this problem. Here's the algorithm:

input credit card number into variable card
get the first digit of the card number (eg. digit = card[0])
if digit equals "4"
    the card issuer "Visa"
elif digit equals "5"
    the card issuer "MasterCard"
elif digit equals "6"
    the card issuer is "Discover"
elif digit equals "3"
    the card issues is "American Express"
else
    the issuer is "Invalid"    
print issuer

Now You Try It

Turn the algorithm into python code


In [ ]:
## TODO: Write your code here

IMPORTANT Make sure to test your code by running it 5 times. You should test issuer and also the "Invalid Card" case.

Introducing the Write - Refactor - Test - Rewrite approach

It would be nice to re-write this code to use a function. This can seem daunting / confusing for beginner programmers, which is why we teach the Write - Refactor - Test - Rewrite approach. In this approach you write the ENTIRE PROGRAM and then REWRITE IT to use functions. Yes, it's inefficient, but until you get comfotable thinking "functions first" its the best way to modularize your code with functions. Here's the approach:

  1. Write the code
  2. Refactor (change the code around) to use a function
  3. Test the function by calling it
  4. Rewrite the original code to use the new function.

We already did step 1: Write so let's move on to:

Step 2: refactor

Let's strip the logic out of the above code to accomplish the task of the function:

  • Send into the function as input a credit card number as a str
  • Return back from the function as output the issuer of the card as a str

To help you out we've written the function stub for you all you need to do is write the function body code.


In [ ]:
def CardIssuer(card):
    '''This function takes a card number (card) as input, and returns the issuer name as output'''
    ## TODO write code here they should be the same as lines 3-13 from the code above
    
    # the last line in the function should return the output
    return issuer

Step 3: Test

You wrote the function, but how do you know it works? The short answer is unless you write code to test your function you're simply guessing!

Testing our function is as simple as calling the function with input values where WE KNOW WHAT TO EXPECT from the output. We then compare that to the ACTUAL value from the called function. If they are the same, then we know the function is working as expected!

Here are some examples:

WHEN card='40123456789' We EXPECT CardIssuer(card) to return Visa
WHEN card='50123456789' We EXPECT CardIssuer(card) to return MasterCard
WHEN card='60123456789' We EXPECT CardIssuer(card) to return Discover
WHEN card='30123456789' We EXPECT CardIssuer(card) to return American Express
WHEN card='90123456789' We EXPECT CardIssuer(card) to return Invalid Card

Now you Try it!

Write the tests based on the examples:


In [ ]:
# Testing the CardIssuer() function
print("WHEN card='40123456789' We EXPECT CardIssuer(card) to return Visa ACTUAL", CardIssuer("40123456789"))
print("WHEN card='50123456789' We EXPECT CardIssuer(card) to return MasterCard ACTUAL", CardIssuer("50123456789"))

## TODO: You write the remaining 3 tests, you can copy the lines and edit the values accordingly

Step 4: Rewrite

The final step is to re-write the original program, but use the function instead. The algorithm becomes

input credit card number into variable card
call the CardIssuer function with card as input, issuer as output
print issuer

Now You Try It!


In [ ]:
# TODO Re-write the program here, calling our function.

Functions are abstractions. Abstractions are good.

Step on the accellerator and the car goes. How does it work? Who cares, it's an abstraction! Functions are the same way. Don't believe me. Consider the Luhn Check Algorithm: https://en.wikipedia.org/wiki/Luhn_algorithm

This nifty little algorithm is used to verify that a sequence of digits is possibly a credit card number (as opposed to just a sequence of numbers). It uses a verfication approach called a checksum to as it uses a formula to figure out the validity.

Here's the function which given a card will let you know if it passes the Luhn check:


In [ ]:
# Todo: execute this code

def checkLuhn(card):
    ''' This Luhn algorithm was adopted from the pseudocode here: https://en.wikipedia.org/wiki/Luhn_algorithm'''
    total = 0
    length = len(card)
    parity = length % 2
    for i in range(length):
        digit = int(card[i])
        if i%2 == parity:
            digit = digit * 2
            if digit > 9:
                digit = digit -9
        total = total + digit
    return total % 10 == 0

Is that a credit card number or the ramblings of a madman?

In order to test the checkLuhn() function you need some credit card numbers. (Don't look at me... you ain't gettin' mine!!!!) Not to worry, the internet has you covered. The website: http://www.getcreditcardnumbers.com/ is not some mysterious site on the dark web. It's a site for generating "test" credit card numbers. You can't buy anything with these numbers, but they will pass the Luhn test.

Grab a couple of numbers and test the Luhn function as we did with the CardIssuer() function. Write at least to tests like these ones:

WHEN card='5443713204330437' We EXPECT checkLuhn(card) to return True
WHEN card='5111111111111111' We EXPECT checkLuhn(card) to return False

In [ ]:
#TODO Write your two tests here

Putting it all together

Finally use your two functions to write the following program. It will ask for a series of credit card numbers, until you enter 'quit' for each number it will output whether it's invalid or if valid name the issuer.

Here's the Algorithm:

loop
    input a credit card number
    if card = 'quit' stop loop
    if card passes luhn check
        get issuer
        print issuer
    else
        print invalid card

Now You Try It


In [ ]:
## TODO Write code here

Metacognition

Please answer the following questions. This should be a personal narrative, in your own voice. Answer the questions by double clicking on the question and placing your answer next to the Answer: prompt.

Questions

  1. Record any questions you have about this lab that you would like to ask in recitation. It is expected you will have questions if you did not complete the code sections correctly. Learning how to articulate what you do not understand is an important skill of critical thinking.

Answer:

  1. What was the most difficult aspect of completing this lab? Least difficult?

Answer:

  1. What aspects of this lab do you find most valuable? Least valuable?

Answer:

  1. Rate your comfort level with this week's material so far.

1 ==> I can do this on my own and explain how to do it.
2 ==> I can do this on my own without any help.
3 ==> I can do this with help or guidance from others. If you choose this level please list those who helped you.
4 ==> I don't understand this at all yet and need extra help. If you choose this please try to articulate that which you do not understand.

Answer:


In [ ]:
# SAVE YOUR WORK FIRST! CTRL+S
# RUN THIS CODE CELL TO TURN IN YOUR WORK!
from ist256.submission import Submission
Submission().submit()