Lab 1: Functions, Control

Due by 11:59pm on Wednesday, August 30.

Starter Files

Download lab01.zip. Inside the archive, you will find starter files for the questions in this lab, along with a copy of the Ok autograder.

For quickly generating ok commands, you can now use the ok command generator.

Quick Logistics Review

Using Python

When running a Python file from the terminal, you can use options on the command line to inspect your code further. Here are a few that will come in handy. If you want to learn more about other Python command-line options, take a look at the documentation.

  1. Using no command-line options will run the code in the file you provide and return you to the command line. For example, if we want to run lab01.py this way, we would write in the terminal:

    python3 lab01.py
  2. -i: The -i option runs your Python script, then opens an interactive session. In an interactive session, you run Python code line by line and get immediate feedback instead of running an entire file all at once. To exit, type exit() into the interpreter prompt. You can also use the keyboard shortcut Ctrl-D on Linux/Mac machines or Ctrl-Z Enter on Windows.

    If you edit the Python file while running it interactively, you will need to exit and restart the interpreter in order for those changes to take effect.

    Here's how we can run lab01.py interactively:

    python3 -i lab01.py
  3. -m doctest: Runs doctests in a particular file. Doctests are surrounded by triple quotes (""") within functions.

    Each test in the file consists of >>> followed by some Python code and the expected output (though the >>> are not seen in the output of the doctest command).

    To run doctests for lab01.py, we can run:

     python3 -m doctest lab01.py

    When our code passes all of the doctests, no output is displayed. Otherwise, the number of tests that fail will be displayed.


Using OK

In 61A, we use a program called Ok for autograding labs, homeworks, and projects. You should have Ok in the starter files downloaded at the start of this lab. For more information on using Ok commands, learn more here.

You can quickly generate most ok commands at ok-help.

To use Ok to run doctests for a specified function, run the following command:

python3 ok -q <specified function>

By default, only tests that did not pass will show up. You can use the -v option to show all tests, including tests you have passed:

python3 ok -v

You can also use the debug printing feature in OK by writing

print("DEBUG:", x)

Pair Programming

You can use this lab as a way to try out pair programming. Check out the pair programming page.

Topics

Consult this section if you need a refresher on the material for this lab. It's okay to skip directly to the questions and refer back here should you get stuck.

Division, Floor Div, and Modulo

Let's compare the different division-related operators in Python 3:

True Division: /
(decimal division)
Floor Division: //
(integer division)
Modulo: %
(remainder)
>>> 1 / 5
0.2

>>> 25 / 4
6.25

>>> 4 / 2
2.0

>>> 5 / 0
ZeroDivisionError
>>> 1 // 5 # truncate result of true division
0

>>> 25 // 4
6

>>> 4 // 2
2

>>> 5 // 0
ZeroDivisionError
>>> 1 % 5
1

>>> 25 % 4
1

>>> 4 % 2
0

>>> 5 % 0
ZeroDivisionError

A ZeroDivisionError occurs when dividing by 0.

One useful technique involving the % operator is to check whether a number x is divisible by another number y:

x % y == 0

For example, in order to check if x is an even number:

x % 2 == 0

Functions

A function gives a name to the series of statements in its body, and those statements are executed every time the function is called using a call expression. The arguments provided when the function is called give values to the formal paramters of the function.

Here's a function that takes two arguments and names them x and y:

def diff(x, y):
    if x > y:
        x, y = y, x
    return y - x

Here's a function that takes no arguments, but refers to a global name x:

def triple_global_x():
    return 3 * x

>>> x = 4
>>> triple_global_x()
12
>>> x = 6
>>> triple_global_x()
18

To return two values, write one return statement that has two expressions separated by a comma. Use multiple assignment (two names to the left of =) to give a name to each of these values.

def double_triple(x):
    return 2*x, 3*x

ten, fifteen = double_triple(5)

Call expressions

A call expression applies a function and evaluates to the function's return value.

The syntax of a function call:

  add   (  1 + 1   ,    3   )
   |         |          |
operator  operand    operand

Every call expression requires a set of parentheses containing its comma-separated operands. An operand is an expression, and its value is an argument.

To evaluate a function call:

  1. Evaluate the operator, and then the operands (from left to right).
  2. Apply the function (the value of the operator) to the arguments (the values of the operands).

return and print

Most functions that you define will contain a return statement that provides the value of the call expression used to call the function.

When Python executes a return statement, the function call terminates immediately. If Python reaches the end of the function body without executing a return statement, the function will automatically return None.

In contrast, the print function is used to display values in the Terminal. Unlike a return statement, when Python evaluates a print expression, the function does not terminate immediately.

def what_prints():
    print('Hello World!')
    return 'Exiting this function.'
    print('61A is awesome!')

>>> what_prints()
Hello World!
'Exiting this function.'

Notice also that print will display text without the quotes, but return will preserve the quotes.


Control

Boolean Operators

Python supports three boolean operators: and, or, and not:

>>> a = 4
>>> a < 2 and a > 0
False
>>> a < 2 or a > 0
True
>>> not (a > 0)
False
  • and evaluates to True only if both operands evaluate to True. If at least one operand is False, then and evaluates to False.
  • or evaluates to True if at least one operand evaluates to True. If both operands are False, then or evaluates to False.
  • not evaluates to True if its operand evaluates to False. It evaluates to False if its operand evalutes to True.

What do you think the following expression evaluates to? Try it out in the Python interpreter.

>>> True and not False or not True and False

It is difficult to read complex expressions, like the one above, and understand how a program will behave. Using parentheses can make your code easier to understand. Python interprets that expression in the following way:

>>> (True and (not False)) or ((not True) and False)

This is because boolean operators, like arithmetic operators, have an order of operation:

  • not has the highest priority
  • and
  • or has the lowest priority

In Python, False is not the only false value. False values include the following values (more to come):

False, 0, '', None

Everything else is a true value.

Sometimes true values are called truthy values and false values are called falsey values, since True is not the only true value.

If Statements

You can review the syntax of if statements in Section 1.5.4 of Composing Programs.

Tip: We sometimes see code that looks like this:

if x > 3:
    return True
else:
    return False

This can be written more concisely as return x > 3. If your code looks like the code above, see if you can rewrite it more clearly!

While Loops

You can review the syntax of while loops in Section 1.5.5 of Composing Programs.


Error Messages

By now, you've probably seen a couple of error messages. They might look intimidating, but error messages are very helpful for debugging code. The following are some common types of errors:

Error Types Descriptions
SyntaxError Contained improper syntax (e.g. missing a colon after an if statement or forgetting to close parentheses/quotes)
IndentationError Contained improper indentation (e.g. inconsistent indentation of a function body)
TypeError Attempted operation on incompatible types (e.g. trying to add a function and a number) or called function with the wrong number of arguments
ZeroDivisionError Attempted division by zero

Using these descriptions of error messages, you should be able to get a better idea of what went wrong with your code. If you run into error messages, try to identify the problem before asking for help. You can often Google unfamiliar error messages to see if others have made similar mistakes to help you debug.

For example:

>>> square(3, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: square() takes 1 positional argument but 2 were given

Note:

  • The last line of an error message tells us the type of the error. In the example above, we have a TypeError.
  • The error message tells us what we did wrong -- we gave square 2 arguments when it can only take in 1 argument. In general, the last line is the most helpful.
  • The second to last line of the error message tells us on which line the error occurred. This helps us track down the error. In the example above, TypeError occurred at line 1.

Required Questions


Getting Started Videos

These videos may provide some helpful direction for tackling the coding problems on this assignment.

To see these videos, you should be logged into your berkeley.edu email.

YouTube link

Syllabus Quiz

Q1: Syllabus Quiz

Please fill out the Syllabus Quiz, which is based off of our policies found on the course syllabus.

What Would Python Display? (WWPD)

Q2: WWPD: Control

Use Ok to test your knowledge with the following "What Would Python Display?" questions:

python3 ok -q control -u

>>> def xk(c, d):
...     if c == 4:
...         return 6
...     elif d >= 4:
...         return 6 + 7 + c
...     else:
...         return 25
>>> xk(10, 10)
______
23
>>> xk(10, 6)
______
23
>>> xk(4, 6)
______
6
>>> xk(0, 0)
______
25
>>> def how_big(x):
...     if x > 10:
...         print('huge')
...     elif x > 5:
...         return 'big'
...     elif x > 0:
...         print('small')
...     else:
...         print("nothing")
>>> how_big(7)
______
'big'
>>> how_big(12)
______
huge
>>> how_big(1)
______
small
>>> how_big(-1)
______
nothing

Hint: Make sure your while loop conditions eventually evaluate to a false value, or they'll never stop! Typing Ctrl-C will stop infinite loops in the interpreter.

>>> n = 3
>>> while n >= 0:
...     n -= 1
...     print(n)
______
2 1 0 -1
>>> positive = 28
>>> while positive:
...    print("positive?")
...    positive -= 3
______
Infinite Loop
>>> negative = -12
>>> while negative:
...    if negative + 6:
...        print(negative)
...    negative += 3
______
-12 -9 -3

Q3: Debugging Quiz

The following is a quick quiz on different debugging techniques that will be helpful for you to use in this class. You can refer to the debugging article to answer the questions.

Use Ok to test your understanding:

python3 ok -q debugging-quiz -u

Code Writing Questions

Q4: Falling Factorial

Let's write a function falling, which is a "falling" factorial that takes two arguments, n and k, and returns the product of k consecutive numbers, starting from n and working downwards. When k is 0, the function should return 1.

def falling(n, k):
    """Compute the falling factorial of n to depth k.

    >>> falling(6, 3)  # 6 * 5 * 4
    120
    >>> falling(4, 3)  # 4 * 3 * 2
    24
    >>> falling(4, 1)  # 4
    4
    >>> falling(4, 0)
    1
    """
    "*** YOUR CODE HERE ***"

Use Ok to test your code:

python3 ok -q falling

Q5: Divisible By k

Write a function divisible_by_k that takes positive integers n and k. It prints all positive integers less than or equal to n that are divisible by k from smallest to largest. Then, it returns how many numbers were printed.

def divisible_by_k(n, k):
    """
    >>> a = divisible_by_k(10, 2)  # 2, 4, 6, 8, and 10 are divisible by 2
    2
    4
    6
    8
    10
    >>> a
    5
    >>> b = divisible_by_k(3, 1)  # 1, 2, and 3 are divisible by 1
    1
    2
    3
    >>> b
    3
    >>> c = divisible_by_k(6, 7)  # There are no integers up to 6 divisible by 7
    >>> c
    0
    """
    "*** YOUR CODE HERE ***"

Use Ok to test your code:

python3 ok -q divisible_by_k

Q6: Sum Digits

Write a function that takes in a nonnegative integer and sums its digits. (Using floor division and modulo might be helpful here!)

def sum_digits(y):
    """Sum all the digits of y.

    >>> sum_digits(10) # 1 + 0 = 1
    1
    >>> sum_digits(4224) # 4 + 2 + 2 + 4 = 12
    12
    >>> sum_digits(1234567890)
    45
    >>> a = sum_digits(123) # make sure that you are using return rather than print
    >>> a
    6
    """
    "*** YOUR CODE HERE ***"

Use Ok to test your code:

python3 ok -q sum_digits

Check Your Score Locally

You can locally check your score on each question of this assignment by running

python3 ok --score

This does NOT submit the assignment! When you are satisfied with your score, submit the assignment to Gradescope to receive credit for it.

Submit

Make sure to submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. For a refresher on how to do this, refer to Lab 00.

Optional Questions

These questions are optional, but you must complete them in order to be checked off before the end of the lab period. They are also useful practice!

Q7: WWPD: What If?

Use Ok to test your knowledge with the following "What Would Python Display?" questions:

python3 ok -q if-statements -u

Hint: print (unlike return) does not cause the function to exit.

>>> def ab(c, d):
...     if c > 5:
...         print(c)
...     elif c > 7:
...         print(d)
...     print('foo')
>>> ab(10, 20)
______
10 foo
>>> def bake(cake, make):
...     if cake == 0:
...         cake = cake + 1
...         print(cake)
...     if cake == 1:
...         print(make)
...     else:
...         return cake
...     return make
>>> bake(0, 29)
______
1 29 29
>>> bake(1, "mashed potatoes")
______
mashed potatoes 'mashed potatoes'

Q8: Double Eights

Write a function that takes in a number and determines if the digits contain two adjacent 8s.

def double_eights(n):
    """Return true if n has two eights in a row.
    >>> double_eights(8)
    False
    >>> double_eights(88)
    True
    >>> double_eights(2882)
    True
    >>> double_eights(880088)
    True
    >>> double_eights(12345)
    False
    >>> double_eights(80808080)
    False
    """
    "*** YOUR CODE HERE ***"

Use Ok to test your code:

python3 ok -q double_eights