Program design: screen time
About this video
The instructor designs a program to analyze a day of phone screen-time data stored as a list, where each element is a minute holding an app name or an empty string when idle. He writes count_minutes (with continue and an optional list of excluded apps), count_sessions (tracking the previous element, initialized to the empty string), and an average session length function that avoids a zero division error, testing each with small test cases.
You'll be able to
- iterate over a list and use continue to skip elements I don't want to count.
- track the previous element in a loop to detect where something new starts.
- design small test cases, including edge cases, to check a function's results.
- guard against a zero division error.
Key words
- continue
- A statement that jumps straight to the next loop iteration, skipping the rest of the loop body.
- in operator
- Checks whether a value is in a list, giving True or False.
- screen time session
- A run of active minutes in a row, ended by idle time.
- ZeroDivisionError
- The error raised when a program tries to divide by zero.
- module
- A separate Python file of code or data that other files can import.
Transcript
- [Instructor] Let's design a program with lists. Say we've been tracking our screen time usage on our phone and we wanna take a closer look at that data to better understand our usage patterns. I wanna know how many minutes I spend on my phone every day and how many separate times I pick up my phone to do something, which I'll call screen time sessions.
The tracking software I'm using formats my data in a list where each element represents a minute of the day. Each minute it records the name of the app that I'm using, or if my phone is idle, it records an empty string. Here, I've downloaded the data for a single day.
I can split a long list like this over multiple lines as long as I start and end with a square bracket, just like we do with parentheses. This quickly clutters up our program, so it's good practice to put our data in a separate file. Then, anyone who needs the data can just import the module.
Now for our data analysis, let's create a new module to put all of our functions. We'll start with a function to count our total minutes of screen time. It should take in as a parameter a list of that raw usage data, and it should return out a count of the active minutes.
Now, the total number of minutes, of course, is just the length of the list, but we don't wanna count minutes where the phone is idle. So we'll start by iterating over the list and keeping a basic count. Since we don't care about the particular index, we can just iterate by element.
We'll initialize our count to zero before the loop, increment it on each iteration, and return its final value. But we don't wanna count every element. We only wanna count the minutes where we're using an app. So if the element is equal to the empty string, we can skip it using the continue statement, meaning we immediately jump to the next iteration without executing this increment line.
Ooh, okay. Let's test our function. We'll go back to the main file and import our screen_time module. We can call our count_minutes function on our real usage data, but how do we know if this number makes sense? Instead, let's try calling it with some smaller test cases where we can actually verify the answer.
If every minute is idle, we should get back a count of zero. If some minutes have an app name, we should count just those. And if all minutes are active, we should count all of them. One quick thought though is that some of my screen time is mandated, like I have to be on the Zoom call for work.
I'm mostly interested in my personal screen time, so what if I had the option to specify apps to exclude from my count? I can add a second parameter that takes in a list of apps. And if I wanna count all apps, like before, I can pass in an empty list. So back to my function definition, I'll add that new parameter.
And then during our list iteration, we wanna skip that element if it's one of these apps. We can use the in operator to check if our current app is in the list of excluded apps. All right, next analysis. Let's write a count_sessions function. It should take in our list of usage data and return out the number of distinct phone sessions.
So if I check my email, listen to some music, watch some videos, message a friend all in a row, that all counts as a single session until I take a break from my phone. As we iterate over the list then, we know we started a new session if our current element is an app name and our previous element was an empty string.
There are several different ways to implement that logic. Here, I'm gonna use a variable to keep track of the previous element. At the end of each iteration then, we just set that variable to the current element. But what do we initialize previous activity to?
Well, our interesting test cases here will be when there's idle time at the beginning or end of the list versus when the first or last element is an app name. Does our function correctly count the first and last sessions? If the first element is an empty string, we don't wanna count a new session.
Log not equal to the empty string will evaluate to false, so we'll correctly not execute this increment. However, if the first element is an app name, we've started a new session, so we do wanna increment the count. That means we need this condition to evaluate to true on the first iteration.
We're covered on the current element not equaling the empty string, but if we want this whole expression to be true, we need to initialize previous activity to the empty string. Then we just need to verify that those two test cases with the last element work. And our function is done.
Last piece, I wanna know my average session length. That is how many minutes I spend on my phone at a time. To calculate that, I can justify my total minutes of screen time by my number of sessions, which conveniently I already have functions for. So it will nest both of those function calls, divide them, and return the result, which I'll round to the nearest whole number.
Let's run through our test cases again. And, oh, we have a zero division error. So if we're dividing by 0, that must mean our number of sessions is zero, which might be a valid case if we're offline for a while. To avoid the error, we can just check if the number of sessions is zero, in which case the average session length should just be zero.
Based on this day's results, maybe I decide I wanna spend less time on my phone per session, or maybe I decide to expand my analysis, whether that's excluding work apps from my session calculations too or downloading more of my usage data to compare results across multiple days.
Video © Khan Academy, used under CC BY-NC-SA. Watch on Khan Academy. Puzzicle is not affiliated with Khan Academy.