4b. Prof. Rosenthal’s Review#

A review of Chapter 4: Functions and Interfaces, for students who have already studied the chapter. Use the two lists under Concepts covered as a checklist (click a list’s title to hide it), then work through the Questions, which go from easy to hard. Each question has a suggested answer under Answer. Try the question first, then open the Answer.

Run this page on Colab

Concepts covered#

Questions#

Some questions draw pictures with jupyturtle, a small turtle-graphics module for Jupyter notebooks. The turtle starts in the middle of the canvas, facing east (to the right). make_turtle() starts a new drawing, forward(d) moves the turtle d units while drawing a line, left(a) and right(a) turn it a degrees, and penup() and pendown() stop and restart the drawing.

The setup cell below downloads jupyturtle and imports the functions the questions use.

from os.path import basename, exists

def download(url):
    filename = basename(url)
    if not exists(filename):
        from urllib.request import urlretrieve

        local, _ = urlretrieve(url, filename)
        print("Downloaded " + str(local))
    return filename

download('https://github.com/ramalho/jupyturtle/releases/download/2024-03/jupyturtle.py');

import math
from jupyturtle import make_turtle, forward, left, right, penup, pendown

Question 1 (easy): what is displayed?#

Predict what this code displays, then open the Answer to check.

for n in range(3, 7):
    print(n, 360 / n)

Question 2 (easy): what is drawn?#

Describe the drawing this code makes, then open the Answer to check.

make_turtle()
for i in range(3):
    forward(60)
    left(120)

Question 3 (easy): write a function#

Write a function called triangle that takes a parameter length and draws an equilateral triangle with that side length.

Start from this header (replace ... with the body):

def triangle(length):
    ...

Examples

make_turtle()
triangle(80)
Turtle drawing
make_turtle()
triangle(30)
Turtle drawing

Question 4 (easy): what is displayed?#

def greet(name):
    """Print a greeting.

    name: string
    """
    print('Hello,', name)

greet('Ada')

Question 5 (easy): what is displayed?#

def describe(shape, sides):
    print('A', shape, 'has', sides, 'sides')

describe('square', 4)
describe(sides=3, shape='triangle')

Question 6 (medium): what is drawn?#

make_turtle()
for i in range(4):
    forward(50)
    right(90)

Question 7 (medium): what happens?#

Assume you have just restarted the notebook and run only the setup cells (at the start of the Questions), and then this code.

from jupyturtle import make_turtle, forward
make_turtle()
forward(50)
jupyturtle.left(90)
forward(50)

Question 8 (medium): what is displayed?#

def inner(angle):
    angle = angle / 2
    print('inner:', angle)

def outer(angle):
    inner(angle)
    print('outer:', angle)

outer(90)

Question 9 (medium): what is displayed?#

def c(x):
    print('c starts with', x)

def b(x):
    print('b starts with', x)
    c(x * 2)
    print('b ends with', x)

def a(x):
    print('a starts with', x)
    b(x + 1)
    print('a ends with', x)

a(3)

Question 10 (medium): write a function#

Write a function called star that takes a parameter length and draws a five-pointed star whose lines have that length.

Hint: the turtle draws 5 lines and turns the same angle after each one. In total it turns around twice (720 degrees).

Start from this header (replace ... with the body):

def star(length):
    ...

Examples

make_turtle()
star(100)
Turtle drawing
make_turtle()
star(50)
Turtle drawing

Question 11 (medium): write a function#

Write a function called row_of_squares that takes n and length and draws n squares in a row, side by side and touching, each with side length length.

Run this cell to define square and jump.

def square(length):
    for i in range(4):
        forward(length)
        left(90)

def jump(length):
    """Move forward length units without drawing."""
    penup()
    forward(length)
    pendown()

Start from this header (replace ... with the body):

def row_of_squares(n, length):
    ...

Examples (jump(-150) first moves the turtle left, so the row fits on the canvas)

make_turtle(width=400)
jump(-150)
row_of_squares(5, 40)
Turtle drawing
make_turtle()
jump(-120)
row_of_squares(3, 60)
Turtle drawing

Question 12 (medium): write a function with a docstring#

Write a function called staircase that takes steps and size and draws a staircase going up and to the right: for each step, it goes up size units and then right size units. Give it a docstring that explains its interface (what it does and what each parameter means).

Start from this header (replace ... with the body):

def staircase(steps, size):
    ...

Examples

make_turtle()
staircase(4, 15)
Turtle drawing
make_turtle()
staircase(2, 30)
Turtle drawing

help displays a function’s docstring. Yours will have your own wording; for example:

help(staircase)
Help on function staircase in module __main__:

staircase(steps, size)
    Draw a staircase going up and to the right.

    steps: number of steps (a positive integer)
    size: height and depth of each step

Question 13 (hard): what is displayed?#

def square_txt(length):
    print('square', length)

def growing(n, length):
    for i in range(n):
        square_txt(length)
        length = length * 2
    print('growing ends with', length)

length = 5
growing(3, length)
print('outside:', length)

Question 14 (hard): preconditions#

polygon’s docstring states its preconditions.

Run this cell to define polygon.

def polygon(n, length):
    """Draw a regular polygon.

    Preconditions: n is a positive integer; length is a positive number.
    """
    angle = 360 / n
    for i in range(n):
        forward(length)
        left(angle)

Two correct ways to use it:

make_turtle()
polygon(4, 40)
Turtle drawing
make_turtle()
polygon(n=6, length=25)
Turtle drawing

For each of the three parts, predict what happens. Then say whether the bug is in the caller or in polygon.

Part a

make_turtle()
polygon(4.5, 20)

Part b

make_turtle()
polygon(0, 20)

Part c

make_turtle()
polygon(-4, 20)

Question 15 (hard): keyword arguments#

Run this cell to define describe.

def describe(shape, sides):
    print('A', shape, 'has', sides, 'sides')

Two correct ways to call it:

describe('hexagon', 6)
A hexagon has 6 sides
describe(sides=5, shape='pentagon')
A pentagon has 5 sides

Each of the next three calls is wrong in a different way. Predict the error for each, then open the Answer to check.

Part a

describe(shape='square', 4)

Part b

describe('square', shape='box')

Part c

describe('square', size=4)

Question 16 (hard): write a function#

Write a function called spiral that takes n, length, angle and increase. It draws n line segments, turning left angle degrees after each one. The first segment has length length, and each segment is increase units longer than the one before.

Start from this header (replace ... with the body):

def spiral(n, length, angle, increase):
    ...

Examples

make_turtle(delay=0)
spiral(40, 2, 30, 1)
Turtle drawing
make_turtle(delay=0)
spiral(20, 5, 90, 5)
Turtle drawing

Question 17 (hard): write a function#

Write a function called grid that takes rows, cols and size and draws a grid of squares, rows high and cols wide, each with side length size. The turtle starts at the bottom-left corner of the grid, facing east.

Hint: to get from the end of one row to the start of the next, use jump (with a negative length to go back), left and right.

Start from this header (replace ... with the body):

def grid(rows, cols, size):
    ...

Examples

make_turtle(height=220, delay=0)
jump(-75)
grid(3, 5, 30)
Turtle drawing
make_turtle(delay=0)
jump(-60)
grid(2, 4, 30)
Turtle drawing

This question uses jump and square from Question 11.

Question 18 (hard): refactor#

These two functions work, but they repeat almost all of their code.

def triangle_row(n, length):
    for i in range(n):
        for j in range(3):
            forward(length)
            left(120)
        jump(length)

def square_row(n, length):
    for i in range(n):
        for j in range(4):
            forward(length)
            left(90)
        jump(length)

Refactor them: write one general function, polygon_row(sides, n, length), that draws a row of n regular polygons with sides sides. Then rewrite triangle_row and square_row to use it, without changing how they are called or what they draw.

Start from this header (replace ... with the body):

def polygon_row(sides, n, length):
    ...

def triangle_row(n, length):
    ...

def square_row(n, length):
    ...

Examples (they draw the same pictures before and after the refactoring)

make_turtle(delay=0)
jump(-80)
triangle_row(4, 40)
Turtle drawing
make_turtle(delay=0)
jump(-60)
square_row(3, 40)
Turtle drawing

This question uses jump from Question 11, and polygon from Question 14.

Question 19 (hard): generalize a function#

This function draws an arc (part of a circle) with the given radius, spanning angle degrees, as 30 short straight lines:

def arc(radius, angle):
    arc_length = 2 * math.pi * radius * angle / 360
    n = 30
    length = arc_length / n
    step_angle = angle / n
    for i in range(n):
        forward(length)
        left(step_angle)

It always uses 30 lines: for a big circle each line is long and the circle looks jagged, and for a tiny one most lines are too short to see.

  1. Write arc_n(radius, angle, n), which does the same but draws n lines.

  2. Write circle(radius), which uses arc_n to draw a full circle, choosing n from the radius so that each line is about 3 units long, with at least 10 lines. (int() converts a float to an integer by dropping the fraction.)

Start from this header (replace ... with the body):

def arc_n(radius, angle, n):
    ...

def circle(radius):
    ...

Examples

make_turtle(delay=0)
arc_n(30, 180, 3)
Turtle drawing
make_turtle(delay=0)
arc_n(30, 180, 30)
Turtle drawing
make_turtle(delay=0)
circle(30)
Turtle drawing

Summary and questions by Prof. Y. Rosenthal, based on Think Python: 3rd Edition by Allen B. Downey. Text license: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International