Exercises#
This page contains three take-home exercises that reinforce the concepts from Lecture 4. Each exercise asks you to write code from scratch based on a specification – no starter code is provided.
All files should be created inside your lecture4/ workspace folder.
Exercise 1 – Function Basics and Arguments
Goal
Demonstrate your understanding of function definitions, multiple return
values, default arguments, keyword arguments, *args, and **kwargs
by implementing a set of utility functions for robot configuration.
Specification
Create a file lecture4/robot_config.py that implements the following
functions. Each function must include type hints and a Google-style
docstring.
``compute_distance`` – Takes two tuples representing 2D coordinates
(x1, y1)and(x2, y2). Returns the Euclidean distance rounded to 2 decimal places. Use the formula:sqrt((x2 - x1)**2 + (y2 - y1)**2). Importsqrtfrom themathmodule.``configure_motor`` – Takes a required
name(str) and optional keyword arguments:speed(float, default1.0),direction(str, default"forward"), andenabled(bool, defaultTrue). Returns a dictionary with keys"name","speed","direction", and"enabled".``compute_statistics`` – Takes
*args(any number of floats). Returns a tuple of(count, total, average)rounded to 2 decimal places. If no arguments are given, return(0, 0.0, 0.0).``build_command`` – Takes a required
action(str) and**kwargsfor additional parameters. Returns a formatted string:"ACTION: <action> | PARAMS: key1=val1, key2=val2, ...". If no kwargs are given, the params section should say"none".``swap_coordinates`` – Takes two tuples
(x1, y1)and(x2, y2)and returns them swapped as a tuple of tuples:((x2, y2), (x1, y1)). Demonstrate tuple unpacking when calling.
In the if __name__ == "__main__" block, call each function with
example arguments and print the results with labels.
Expected output:
=== Distance ===
Distance from (0, 0) to (3, 4): 5.0
=== Motor Configuration ===
Default: {'name': 'left_wheel', 'speed': 1.0, 'direction': 'forward', 'enabled': True}
Custom: {'name': 'right_wheel', 'speed': 2.5, 'direction': 'reverse', 'enabled': False}
=== Statistics ===
Stats for (10.5, 20.3, 30.7, 40.1): (4, 101.6, 25.4)
Stats for (): (0, 0.0, 0.0)
=== Command Builder ===
build_command('move', x=10, y=20): ACTION: move | PARAMS: x=10, y=20
build_command('stop'): ACTION: stop | PARAMS: none
=== Swap ===
Before: a=(1, 2), b=(3, 4)
After: a=(3, 4), b=(1, 2)
Deliverables
lecture4/robot_config.pyThe program must run without errors and produce output matching the expected format above.
Exercise 2 – Scope and Pass-by-Assignment
Goal
Explore variable scoping (LEGB rule), the global and nonlocal
keywords, and pass-by-assignment behavior with mutable and immutable
objects.
Specification
Create a file lecture4/scope_explorer.py that demonstrates each
concept below. Each task must print clearly labeled output showing
variable values before and after function calls.
Local vs. Global – Define a global variable
mode = "manual". Write a functionset_mode_local()that creates a local variablemode = "auto"and prints it. After calling the function, print the globalmodeto show it is unchanged.The ``global`` keyword – Write a function
set_mode_global()that uses theglobalkeyword to modify the module-levelmodevariable to"autonomous". Printmodebefore and after the call.Enclosing scope with ``nonlocal`` – Write a function
make_counter()that defines a local variablecount = 0and a nested functionincrement()that usesnonlocalto increasecountby 1 and returns it. Callincrement()three times from insidemake_counter()and print the result each time.Pass-by-assignment with immutable – Write a function
try_modify_int(x: int) -> Nonethat adds 10 toxand prints the result inside the function. Call it withvalue = 5and printvalueafter the call to show it is unchanged.Pass-by-assignment with mutable – Write a function
add_sensor(robot: dict, sensor: str) -> Nonethat appendssensortorobot["sensors"]. Call it and print the robot dictionary before and after to show the in-place modification.Reassignment vs. mutation – Write a function
reassign_list(data: list) -> Nonethat reassignsdatato a new list[99, 99, 99]and prints it inside the function. Call it withoriginal = [1, 2, 3]and printoriginalafter the call to show the original is unchanged.
Expected output:
=== Task 1: Local vs Global ===
Inside set_mode_local(): auto
Global mode after call: manual
=== Task 2: global keyword ===
Before: manual
After set_mode_global(): autonomous
=== Task 3: nonlocal with make_counter ===
Increment 1: 1
Increment 2: 2
Increment 3: 3
=== Task 4: Immutable (int) ===
Inside function: 15
Outside after call: 5
=== Task 5: Mutable (dict) ===
Before: {'name': 'TurtleBot', 'sensors': ['lidar']}
After add_sensor: {'name': 'TurtleBot', 'sensors': ['lidar', 'camera']}
=== Task 6: Reassignment vs Mutation ===
Inside function: [99, 99, 99]
Outside after call: [1, 2, 3]
Deliverables
lecture4/scope_explorer.pyThe program must run without errors and produce output matching the expected format above.
Exercise 3 – Robot Toolkit
Goal
Combine all concepts from Lecture 4 – function definition, arguments, scope, pass-by-assignment, type hints, docstrings, and recursion – to build a toolkit of reusable functions for a robot navigation system.
Specification
Create a file lecture4/robot_toolkit.py that implements the following
functions. Every function must have type hints and a Google-style
docstring.
``create_waypoint`` – Takes
name(str),x(float),y(float), and an optionalpriority(int, default0). Returns a dictionary with keys"name","x","y", and"priority".``compute_path_length`` – Takes a list of waypoints (dicts from
create_waypoint). Computes the total Euclidean distance along the path (from waypoint 0 to 1, 1 to 2, etc.). Returns the total distance rounded to 2 decimal places. If the list has fewer than 2 waypoints, return0.0.``sort_by_priority`` – Takes a list of waypoints and returns a new list sorted by priority in descending order (highest first). The original list must not be modified. Use a loop (do NOT use the built-in
sorted()orlist.sort()). Implement a simple selection sort.``format_waypoint`` – Takes a waypoint dictionary and returns a formatted string:
"[P<priority>] <name> @ (<x>, <y>)". Example:"[P2] charger @ (5.0, 3.0)".``print_path`` – Takes a list of waypoints and an optional
label(str, default"Path"). Prints the label, then each waypoint usingformat_waypoint(), then the total path length usingcompute_path_length().``recursive_distance_sum`` – Takes a list of float distances and returns their sum using recursion (no loops, no
sum()). Base case: empty list returns0.0.
In the if __name__ == "__main__" block:
Create at least 4 waypoints with different priorities.
Store them in a list and print the path using
print_path().Sort by priority and print the sorted path.
Demonstrate
recursive_distance_sum()with a list of segment distances.
Expected output:
=== Original Path ===
Path:
1. [P1] start @ (0.0, 0.0)
2. [P3] obstacle @ (3.0, 4.0)
3. [P0] waypoint_A @ (6.0, 4.0)
4. [P2] charger @ (6.0, 8.0)
Total distance: 12.0
=== Sorted by Priority ===
Priority Path:
1. [P3] obstacle @ (3.0, 4.0)
2. [P2] charger @ (6.0, 8.0)
3. [P1] start @ (0.0, 0.0)
4. [P0] waypoint_A @ (6.0, 4.0)
Total distance: 18.63
=== Recursive Distance Sum ===
Distances: [5.0, 3.0, 4.0]
Recursive sum: 12.0
Deliverables
lecture4/robot_toolkit.pyThe program must run without errors and produce output matching the expected format above.
All calculations must be computed dynamically (no hard-coded results).
Every function must include type hints and a Google-style docstring.