download notebook

Fifteen-minute Friday #3

files needed = None

Fifteen-minute Fridays are brief, nongraded workbooks that provide some extra practice and introduce new topics for self-guided study. This week we are working on

  1. Keyword and default arguments in functions
  2. Python practice

The solutions to the practice problems are at the end of the notebook.

More on functions

Writing functions is an important part of programming. You write the code once, debug it and test it, and then use it whenever you need to. We will also see situations later where we can extend the use of a pandas function by giving it functions of our own to apply to DataFrames. [More on that in a few weeks.]

Let's dig a bit deeper into functions.

Argument types

A function can take inputs, which are called arguments in python and produce outputs. In class, we covered positional arguments. Positional arguments have to be passed to the function in the correct order.

def divider(numerator, denominator):
    """
    Divides numerator by denominator.  
    """
    return numerator/denominator 
# Here numerator = 5 and denominator = 10
divider(5, 10)
0.5
# Here numerator = 10 and denominator = 5
divider(10, 5)
2.0

A disadvantage of positional arguments is that you have to remember what order to pass the values to the function. For simple functions, this is not much to ask.

We can also call a function using keyword arguments. Keyword arguments pass the name of the argument and the argument's values.

divider(numerator=100, denominator=25)
4.0
# Is this 4, or 0.25?
divider(denominator=25, numerator=100)
4.0

When using keyword arguments, the ordering of the arguments does not matter.

We will see keyword arguments in many of the plotting and data management functions we will use in the next few weeks. Here is a simple example.

print('The econ department phone number is:') 
print('608', '263', '2989')
The econ department phone number is:
608 263 2989
# print() has a keyword argument 'sep' that sets the separating character.
print('The econ department phone number is:') 
print('608', '263', '2989', sep='-')
The econ department phone number is:
608-263-2989

In the last line, the print function took 3 positional arguments and one keyword argument. We can set the sep argument to be any character. If you wanted each argument printed on one line, you would set it to \n.

Default arguments

When writing a function, you may define default values for your arguments.

def weight_converter(weight, how='kgtolb'):
    """
    Converts weights to different units. Currently supports pounds to kilograms
    and kilograms to pounds.
    """
    if how == 'kgtolb':
        return weight*2.205
    elif how == 'lbtokg':
        return weight/2.205
# If I do not pass the `how` argument, I get kilos to lbs. 
weight_converter(1.0)
2.205
weight_converter(1.0, how='lbtokg')
0.4535147392290249

Practice

  1. What is the default value of sep in the print() function? What does print's end argument do?

  2. Does the following code work?

print(sep='-', '608', '263', '2989')

What does this tell us about how we can mix positional and keyword arguments?

  1. Write a function named employee_summary that takes three arguments: a dictionary of data, a name, and an argument called extended. Make the default value of extended be False. The other two arguments do not need default values.

If the name is not in the dict, then the function should return a message stating so.

If the name is in the dict and extended==False, then the function should print the employee's name and department. Example: 'Employee Kim is in economics.'

If the name is in the dict and extended==True, then the function should print the employee's name, position, and department. Example: 'Employee Kim is a prof in economics.'

Notice that the first letter of the person's name in the output has been capitalized.

Here is the data dictionary:

data = {'kim':['prof', 'economics'], 'greg':['TA', 'economics'], 
        'bucky':['mascot', 'sports'], 'barry':['coach', 'the football team'], 
        'abe':['president', 'USA'], 'hector':['prof', 'biochemistry']}
  1. Test your function with:
employee_summary(data, 'greg', extended=True)
employee_summary(data, 'goldy')
employee_summary(data, 'barry', extended=False)

General practice

The rest of this notebook does not cover new material, but gives you a chance to practice some more.

  1. Write a function that computes the Fibonacci series and prints them out. (I named my function fibber. That's not very self-documenting. I bet you can do better.) The series is defined as
$$F_0=1, \qquad F_1 = 1, \qquad F_n = F_{n-1} + F_{n-2}$$

That is, once we get past the first two elements, we form the next element by adding together the previous two. The first few numbers are: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...

The function argument is the number of elements of the series to print. Print out the series of numbers to the screen, separated by commas all on the same line. Test by printing out the first 10 numbers. ```python fibber(10)

   Your output should look like: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34

\[There are lots of examples of this code online. Feel free to consult it, but first give it a try yourself and struggle with it. That's how we get better.\]

2. Write a new version of your function that, rather than print the numbers to the screen, returns a list with the first n numbers in the Fibonacci series. 

3. Modify your function from question 2 to check that the argument is an integer that is greater than zero. If it is not, return a message demanding an integer. Check it by passing 1.61803 as an argument. 


```python









Solutions: functions

  1. The default separator is a space. end specifies what to print after the arguments have been printed. The default is \n, which is the end-of-line character.

Try print? and look at the first line of the documentation.

  1. The code does not work. All the positional arguments must be passed before passing keyword arguments.
# Question 3

def employee_summary(data_dict, name, extended=False):
    if name in data_dict:
        if extended == False:
            print('Employee {0} is in {1}.'.format(name.title(), data_dict[name][1]))
        else:
            print('Employee {0} is a {1} in {2}.'.format(name.title(),
                                                         data_dict[name][0], 
                                                         data_dict[name][1]))
    else:
        print('{0} is not an employee.'.format(name.title()))
# Question 4

data = {'kim':['prof', 'economics'], 'greg':['TA', 'economics'], 
        'bucky':['mascot', 'sports'], 'barry':['coach', 'the football team'], 
        'abe':['president', 'USA'], 'hector':['prof', 'biochemistry']}

employee_summary(data, 'greg', extended=True)
employee_summary(data, 'goldy')
employee_summary(data, 'barry', extended=False)
Employee Greg is a TA in economics.
Goldy is not an employee.
Employee Barry is in the football team.

Solutions: general practice

There are other (probably better) ways to write this code than I wrote it. If you did something cool, let me know!

# Question 1

def fibber(n):
    """
    Compute the first n values of the Fibonacci series.
    """
    # Initialize the first two values. 
    f0, f1 = 0, 1

    # We want a space and not an \n after printing.
    # There should not be a comma after the last value.
    for i in range(0, n):
        if i < n-1:
            print('{0},'.format(f0), end=' ')
        else:
            print('{0}'.format(f0), end=' ')

        # Use multiple assignment to update the values.
        f0, f1 = f1, f0 + f1
fibber(10)
0, 1, 1, 2, 3, 5, 8, 13, 21, 34
# Question 2

def fibber_list(n):
    """
    Compute the first n values of the Fibonacci series. Return in a list.
    """
    # This creates an empty list that we can fill up.
    fibs = []

    # Initialize the first two values. 
    f0, f1 = 0, 1

    # We want a space and not an \n after printing.
    # There should not be a comma after the last value.
    for i in range(0, n):
        fibs.append(f0)

        # Use multiple assignment to update the values.
        f0, f1 = f1, f0 + f1
    return fibs
fibber_list(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# Question 3

def fibber_list_err(n):
    """
    Compute the first n values of the Fibonacci series. Return in a list.
    """
    if (type(n) == int) and (n > 0):
        # This creates an empty list that we can fill up.
        fibs = []

        # Initialize the first two values. 
        f0, f1 = 0, 1

        # We want a space and not an \n after printing.
        # There should not be a comma after the last value.
        for i in range(0, n):
            fibs.append(f0)

            # Use multiple assignment to update the values.
            f0, f1 = f1, f0 + f1
        return fibs
    else:
        print('This function demands a positive integer!')
fibber_list_err(1.61803)
This function demands a positive integer!