Bughouse
Congratulations. You're the Head of Technology at Crooked Orbit, a small, slightly chaotic space logistics company run by a crew of questionable astronauts with even more questionable code.
The pay is decent. The codebase is not...
Your job is to work through the issues: bugs, broken functions, things that technically run but really shouldn't.
#1: Name formatter
.capitalize() on each one, I can see it right there in the loop. I don't get it. Can you please have a look? def format_name(full_name):
parts = full_name.split()
for part in parts:
part = part.capitalize()
return " ".join(parts)
print(format_name("alice van den berg"))Expected: Alice Van Den Berg
Got: alice van den berg
What's going wrong, and how do you fix it?
Hint
Think about what actually happens when you reassign a variable inside a for loop. Does changing part affect the list it came from?
One way to fix it
When you write for part in parts, Python gives you each item from the list one at a time. part is just a temporary variable that holds the current item. It's not a direct connection to the list itself.
So when you write part = part.capitalize(), you're replacing what part points to. But parts still holds the original strings. You never actually changed the list.
Here's a way to see it clearly:
parts = ["alice", "van", "den", "berg"]
for part in parts:
part = part.capitalize()
print(parts)
# ['alice', 'van', 'den', 'berg'] # nothing changedTo fix it, you need to build a new list with the capitalised values. A list comprehension does this cleanly:
def format_name(full_name):
parts = full_name.split()
return " ".join(part.capitalize() for part in parts)
print(format_name("alice van den berg"))
# Alice Van Den Bergpart.capitalize() for part in parts goes through each name, capitalises it, and collects the results into a new list. Then .join() puts them back together with spaces.
#2: Top score
None? Every time. I've gone through the loop like five times, the logic looks fine to me. The scores are definitely in there. I don't know what's going on 😅 def highest_score(scores):
best = 0
for score in scores:
if score > best:
best = score
results = [45, 92, 78, 88, 65]
print(f"Top score: {highest_score(results)}")Expected: Top score: 92
Got: Top score: None
What's going wrong, and how do you fix it?
Hint
What does a function return if you never write a return statement?
One way to fix it
The loop is fine. The logic is fine. The problem is that highest_score never actually hands anything back. It finds the best score and then does nothing with it.
In Python, if a function doesn't have a return statement, it returns None automatically. That's what you're printing.
The fix is one line at the end:
def highest_score(scores):
best = 0
for score in scores:
if score > best:
best = score
return best
results = [45, 92, 78, 88, 65]
print(f"Top score: {highest_score(results)}")
# Top score: 92This comes up a lot. The function looks complete because the logic is all there, but without return, the result just disappears when the function finishes.
#3: Budget check
def check_budget(threshold):
spent = input("How much have you spent? ")
if spent >= threshold:
print("Over budget!")
else:
print("You're within budget.")
check_budget(500.0)Error:
TypeError: '>=' not supported between instances of 'str' and 'float'What's going wrong, and how do you fix it?
Hint
What type does input() always return, regardless of what the user types?
One way to fix it
input() always returns a string. It doesn't matter that the user typed a number. Python doesn't know that. It just hands back whatever was typed as text.
So when the code tries to compare spent >= threshold, it's comparing a string to a float, and Python refuses to do that. That's the TypeError.
The fix is to convert the input to a number before comparing it. Use float() to handle decimal values:
def check_budget(threshold):
spent = float(input("How much have you spent? "))
if spent >= threshold:
print("Over budget!")
else:
print("You're within budget.")
check_budget(500.0)
# How much have you spent? 620
# Over budget!Wrapping input() in float() converts the string to a number right away, so the comparison works as expected.
This is one of the most common sources of confusion in Python: input() looks like it's reading a number, but it always gives you a string. You have to convert it yourself.
#4: Cargo label
def cargo_label(item, weight):
label = "Item: " + item + " | Weight: " + weight + "kg"
return label
print(cargo_label("Moon rocks", 42))Error:
TypeError: can only concatenate str (not "int") to strWhat's going wrong, and how do you fix it?
Hint
Python's + operator doesn't automatically convert numbers to strings. What do you need to do before you can join them?
One way to fix it
When you use + to join strings in Python, every value has to be a string. weight is an integer, so Python doesn't know how to attach it to the surrounding text. It refuses rather than guessing.
The fix is to convert weight to a string with str():
def cargo_label(item, weight):
label = "Item: " + item + " | Weight: " + str(weight) + "kg"
return label
print(cargo_label("Moon rocks", 42))
# Item: Moon rocks | Weight: 42kgAn f-string is often cleaner for this kind of thing, since it handles the conversion for you:
def cargo_label(item, weight):
return f"Item: {item} | Weight: {weight}kg"
print(cargo_label("Moon rocks", 42))
# Item: Moon rocks | Weight: 42kgInside {}, Python automatically converts the value to its string representation, so you don't need str() at all.
#5: Passenger manifest
def build_manifest(name, passengers=[]):
passengers.append(name)
return passengers
flight_1 = build_manifest("Pip")
flight_2 = build_manifest("Zee")
flight_3 = build_manifest("Orla")
print(flight_1)
print(flight_2)
print(flight_3)Expected:
['Pip']
['Zee']
['Orla']Got:
['Pip']
['Pip', 'Zee']
['Pip', 'Zee', 'Orla']What's going wrong, and how do you fix it?
Hint
Default argument values in Python are evaluated once, when the function is defined. Not each time the function is called. What does that mean for a mutable object like a list?
One way to fix it
This is one of Python's most well-known surprises. When you write passengers=[] as a default argument, Python creates that list once when the function is defined. Every call that uses the default is sharing the exact same list object. So appending to it in one call affects every future call.
The standard fix is to use None as the default and create a fresh list inside the function:
def build_manifest(name, passengers=None):
if passengers is None:
passengers = []
passengers.append(name)
return passengers
flight_1 = build_manifest("Pip")
flight_2 = build_manifest("Zee")
flight_3 = build_manifest("Orla")
print(flight_1) # ['Pip']
print(flight_2) # ['Zee']
print(flight_3) # ['Orla']Now each call that doesn't pass a list gets its own brand new one.
This applies to any mutable default: lists, dicts, sets. If you want a fresh one each time, don't put it in the signature. Use None and create it inside.

