A challenge: FizzBuzz

Day 5: Exercise Solutions

Python Guru with a screen instead of a face, typing on a computer keyboard with a light orange background to match the day 5 image.

Here are our solutions for the day 5 exercises in the 30 Days of Python series. Make sure you try the exercises yourself before checking out the solutions!

1) Try to approximate the behaviour of the is operator using ==.

To tackle this exercise, we really need to be clear on the difference between these two operators. == is a comparison operator for value equality, while is is a comparison operator for identity. In other words, is checks that two values are exactly the same. We determine this by comparing their memory addresses.

We can find the memory address of a given object using the id function.

If we want to verify that two lists are exactly the same list, we can therefore do something like this:

list_1 = [1, 2, 3, 4, 5]
list_2 = [1, 2, 3, 4, 5]

print(id(list_1) == id(list_2))  # False

Here is an example where the two list are the same:

list_1 = [1, 2, 3, 4, 5]
list_2 = list_1

print(id(list_1) == id(list_2))  # True

We can verify our answer by checking that we get the same result when using is:

list_1 = [1, 2, 3, 4, 5]
list_2 = list_1

print(list_1 is list_2)  # True

2) Try to use the is operator or the id function to investigate the difference between the following:

numbers = [1, 2, 3, 4]
new_numbers = numbers + [5]

numbers = [1, 2, 3, 4]
numbers.append(5)

For this exercise, I'd advise using is for the first piece of code, and id for the second piece of code. The reason I wouldn't use is for the second one, is because we only have a single variable, so it's hard to do a comparison.

For the first piece of code, we can simply check if numbers is the same list as new_numbers like so:

numbers = [1, 2, 3, 4]
new_numbers = numbers + [5]

print(numbers is new_numbers)  # False

In this case, it's False. By using the + operator, we're created a new list, and we've then assigned this new list to new_numbers.

For the second piece of code, we can find the id of numbers before and after the append call:

numbers = [1, 2, 3, 4]
print(id(numbers))  # 140220707722752

numbers.append(5)
print(id(numbers))  # 140220707722752

We can see through manual inspection that these two numbers are the same. If you want to use is here instead, we need to get refer to the original numbers list with an additional variable name like this:

numbers = [1, 2, 3, 4]
numbers_copy = numbers

numbers.append(5)

print(numbers is numbers_copy)  # True

In this case, numbers_copy and numbers start off as the same list. When we modify numbers, we directly modify the list both names refer to. Both lists are updated, and no new lists are created. We can see that the lists are directly modified by looking at the id solution above.

3) Ask the user to enter a number. Tell the user whether the number is positive, negative, or zero.

For this exercise, we need to use a conditional statement.

Our first step should be getting the number from the user and converting it to a float using the float function. You can convert the user input to an integer if you want, but then we can only deal with integral numbers.

user_number = float(input("Please enter a number: "))

Now that we're able to store the user's number in this variable, we can check it against several different cases.

My conditional statement is going to have three branches. Initially, I'm going to check if the number is greater than 0. I think this is the most likely result, so it makes sense to put this first. Next, I'm going to use an elif clause to check if the number is less than 0. Finally, I'm going to use an else clause, which will only trigger if a number is neither greater than 0, nor less than 0. In other words, the number is exactly 0.

user_number = float(input("Please enter a number: "))

if user_number > 0:
    print(f"{user_number} is positive!")
elif user_number < 0:
    print(f"{user_number} is negative!")
else:
    print(f"You entered 0!")

While you can use three separate conditional statements here, like this:

user_number = float(input("Please enter a number: "))

if user_number > 0:
    print(f"{user_number} is positive!")
if user_number < 0:
    print(f"{user_number} is negative!")
if user_number == 0:
    print(f"You entered 0!")

We should avoid this if we have connected conditions. If we have a single conditional statement with several branches, Python only checks the branches until it finds a true condition, which means we potentially save ourselves a lot of unnecessary checks.

4) Write a program to determine whether an employee is owed any overtime. You should ask the user how many hours the employee worked this week, as well as the hourly wage for this employee.

For this exercise, we need to determine whether or not the employee worked more than 40 hours this week. If they did, we need to pay them 110% of their hourly wage for any hours worked over the 40 hours.

Because we have a condition to test here, a conditional statement is a good idea.

Our first step though, is grabbing the values from the user. I'm going to grab the employee's name here, because I want to use it in the output. You can ignore this if you want to.

For both the hours worked, and the hourly wage, I'm going to convert the user input to a floating point number. This is because we can reasonably expect the hourly wage to be something like 16.50, and for people to work fractions of an hour.

employee_name = input("Enter the employee's name: ")
hours_worked = float(input(f"How many hours did {employee_name} work this week? "))
hourly_wage = float(input(f"What is {employee_name}'s hourly wage? "))

Don't forget to put spaces at the end of your prompts!

Now that we have the information we need, we can start working on the logic. First, I'm going to determine whether or not this user worked more than 40 hours, like so:

employee_name = input("Enter the employee's name: ")
hours_worked = float(input(f"How many hours did {employee_name} work this week? "))
hourly_wage = float(input(f"What is {employee_name}'s hourly wage? "))

if hours_worked > 40:
    print(f"{employee_name} worked more than 40 hours.")
else:
    print(f"{employee_name} worked less than 40 hours.")

If everything works at this stage, we can start calculating the pay owed to this employee. Let's start with the case where they worked less than 40 hours, because it's the simpler case.

employee_name = input("Enter the employee's name: ")
hours_worked = float(input(f"How many hours did {employee_name} work this week? "))
hourly_wage = float(input(f"What is {employee_name}'s hourly wage? "))

if hours_worked > 40:
    print(f"{employee_name} worked more than 40 hours.")
else:
    owed_pay = hours_worked * hourly_wage
    print(f"{employee_name} is owed ${owed_pay}.")

At this stage, we have a slight problem. Consider the following user interaction:

Enter the employee's name: John Smith
How many hours did John Smith work this week? 31.75
What is John Smith's hourly wage? 14.56
John Smith is owed $462.28000000000003.

The pay output here can get really ugly. Sometimes we have lots of trailing zeroes, and often we only have one. It would be nice if we could either have no decimal number, or if we could limit the output to two decimal places.

You may have also noticed there's a bit of inaccuracy in the result here. This is because floats can't finitely represent all decimal numbers, so for some decimal values we actually get close approximations, rather than exact values. If you're interested in learning more about this, you can read the first sections of this blog post.

We have two main options for correcting this. First, we can throw away the fractional content of the number by passing the result to int. This will give us a round number, but it will cost us some accuracy:

employee_name = input("Enter the employee's name: ")
hours_worked = float(input(f"How many hours did {employee_name} work this week? "))
hourly_wage = float(input(f"What is {employee_name}'s hourly wage? "))

if hours_worked > 40:
    print(f"{employee_name} worked more than 40 hours.")
else:
    owed_pay = int(hours_worked * hourly_wage)
    print(f"{employee_name} is owed ${owed_pay}.")

An alternative is to make use of some special string formatting syntax. This is really more advanced stuff, but we can limit the amount of decimal places for a float like this:

employee_name = input("Enter the employee's name: ")
hours_worked = float(input(f"How many hours did {employee_name} work this week? "))
hourly_wage = float(input(f"What is {employee_name}'s hourly wage? "))

if hours_worked > 40:
    print(f"{employee_name} worked more than 40 hours.")
else:
    owed_pay = hours_worked * hourly_wage
    print(f"{employee_name} is owed ${owed_pay:.2f}.")

We have another blog post which covers this syntax in more detail. For the rest of this solution, I'm going to use the simpler int approach.

Now that we have that sorted, we can move onto calculating the overtime. I'm going to do this in two stages:

  1. I'm going to calculate 40 times the employee's hourly wage.
  2. I'm going to subtract 40 from the hours worked, and then I'm going to multiply the result by the 110% of the hourly wage.
employee_name = input("Enter the employee's name: ")
hours_worked = float(input(f"How many hours did {employee_name} work this week? "))
hourly_wage = float(input(f"What is {employee_name}'s hourly wage? "))

if hours_worked > 40:
    regular_pay = 40 * hourly_wage
    overtime_pay = (hours_worked - 40) * hourly_wage * 1.1
    owed_pay = int(regular_pay + overtime_pay)

    print(f"{employee_name} is owed ${owed_pay}.")
else:
    owed_pay = int(hours_worked * hourly_wage)
    print(f"{employee_name} is owed ${owed_pay}.")

Because we actually have the same print call in both branches, we can improve this a small amount by moving the print call outside of the conditional statement like this:

employee_name = input("Enter the employee's name: ")
hours_worked = float(input(f"How many hours did {employee_name} work this week? "))
hourly_wage = float(input(f"What is {employee_name}'s hourly wage? "))

if hours_worked > 40:
    regular_pay = 40 * hourly_wage
    overtime_pay = (hours_worked - 40) * hourly_wage * 1.1
    owed_pay = int(regular_pay + overtime_pay)
else:
    owed_pay = int(hours_worked * hourly_wage)

print(f"{employee_name} is owed ${owed_pay}.")

With that, we're done!