CHRISTINE: Imagine that you're an IT specialist working
in a medium-sized company.
Your manager wants to create a daily report that
tracks the use of machines.
Specifically, she wants to know which users are currently
connected to which machines.
It's your job to create the report.
In your company, there's a system
that collects every event that happens
on the machines on the network.
Among the many events collected, it
records each time a user logs in or out of a computer.
With this information, we want to write
a script that generates a report of which users are logged in
to which machines at that time.
Before we jump into solving that problem,
we need to know what information we'll use as input
and what information we'll have as output.
We can work this out by looking at the rest of the system
where our script will live.
In our report scenario, the input is a list of events.
Each event is an instance of the event class.
An event class contains the date when the event happened,
the name of the machine where it happened, the user involved,
and the event type.
In this scenario, we care about the login and logout event
type.
All right, that's good to know, but we
need to know exact names of the attributes.
Otherwise, we won't be able to access them.
The attributes are called date, user, machine, and type.
The event types are strings, and the ones we care about
are login and logout.
With that, we should have enough information
about the input of our script.
Our script will receive a list of event objects
and will access the event's attributes.
We'll then use that information to know if a user is currently
logged into a machine or not.
Let's talk about the output.
We want to generate a report that lists all the machine
names and, for each machine, lists the users that
are currently logged in.
We then want this information printed on the screen.
We've been tasked with generating a report,
and we can decide exactly how we want that report to look.
One option would be to print the name of the machine
at the beginning of the line and then list
the current users on separate lines
and indent it to the right.
Or we could print the machine name followed by a colon
and then the user names separated by commas
all in the same line, and we can probably come up
with something even more fancy.
When formatting a report, it's easy to get caught up
in the making-it-look-good part.
I've fallen into that trap, but what really matters
is how well the script solves the problem.
So it's better to first focus on making the program work.
You can always spend time making the report look nice later.
Let's keep it simple for now, and we'll
go with the approach of printing the machine name followed
by all the current users separated by commas.
OK, we now have a pretty good idea of what we need to do.
We've identified our problem statement,
which is we need to process a list of event objects using
their date, type, machine, and user attributes
to generate a report that lists all users currently logged
in to the machines.
We're off to a great start.
The next step we're going to do is some research
to work out how to best actually do this.
OK, so we have our problem statement,
which helps us understand the problem and focus our approach.
We know we have to input a list of event objects
and evaluate these objects' attributes to output
a report of all the users currently logged
in to a machine.
Now it's time for step two, the research.
We're going to consider all the tools
we have available to help us solve the problem.
To find out which users are currently logged into machines,
we need to check when they logged in
and when they logged out.
If a user logged in to a machine and then logged out,
they're no longer logged in to it.
But if they didn't log out yet, they're still logged in.
I know we're stating the obvious here,
but in programming, it is super important
to be clear on the parameters.
Also, knowing this tells us that to solve this correctly,
it's vital that we process the events in chronological order.
If they're not, we can get the logout event
before the corresponding login event,
and our code may do unpredictable things.
And no one likes unpredictable code.
So how do we sort lists in Python?
We'll need to do some research.
Type "sort lists in Python" into your favorite search engine,
and you'll get a bunch of results
that mentioned the list sort method and the sorted function.
The difference between these two options
is that the sort method modifies the list it's executed on,
while the sorted function returns
a new list that's been sorted.
Apart from that, they work the exact same way.
Let's check out this difference in action.
First, we'll create a list of numbers
and call the sort method to sort the list.
You can see here that the elements of the list
have been sorted.
Let's try a different example now using the sorted function.
We'll create a list of names.
Then we'll print the output of the sorted function.
Let's print the original list again
to check that it didn't change.
So you can see that the original list wasn't modified.
The sorted function returned a new sorted list,
but the original was left untouched.
Nice.
We now know how to sort things in Python.
For this problem, it's fine to modify the original list,
so we'll use the sort method.
But wait, see how both these options
sorted the list alphabetically?
That's the default approach Python takes.
But what if we wanted to organize our lists
by a different criteria?
Again, if we take a look at the documentation we found online,
we'll see that the sort method can
take a couple of parameters.
One of these parameters is called key,
and it lets us use a function as the sorting key.
Let's try this out on our list of names.
Instead of sorting alphabetically,
we could sort by the length of each string.
Do you remember which function we can use to do that?
Yep, we can pass the len function as the key.
All right, we now know how to order elements of a list
based on the return value of a function.
In our report scenario, we know that our elements will
be instances of event class, and we
want to order by date, which is an attribute of the event
class.
One way we could do this is to write a function
called get_event_date, which returns the date stored
in the event object.
We could also create this as a method in the event class
if we had access to modifying the class,
but since we're working with a bigger system that generates
these events, we'll assume that we can't just
add a method to the class.
So we'll create our own function instead.
How does this sound?
Is it all making sense?
Remember that there are various paths
we could take to solve this problem,
but some are better than others.
So it's important to understand why
we chose the options we did.
Feel free to take some time on your own
to explore the possibilities and understand what we're doing.
OK, you're doing great with this so far.
We've already defined our problem statement
and then researched options to figure out
what tools we have available and which are best for the job.
Now it's time to plan our approach.
So we know that our input will be a list of events,
and we'll sort them by time.
Each event in that list will include a machine name,
a username, and tell us whether the event is
a login or a logout.
We want our script to keep track of users
as they log in and out of machines.
So how can we do this?
Let's think about what we'll do for each event
and see if we can figure out the best strategy.
When we process an event, we'll see that someone
interacted with a machine.
If it's a login, we want to add it
to the group of users logged in to that machine.
If it's a logout, we want to remove it
from the group of users logged in to the machine.
In this scenario, it makes sense to use a set
to store the current users, adding new users at login time
and removing them at logout time.
Great, but if the current users of a given machine
are stored in a set, how do we know which set corresponds
to the machine we're looking for?
The easiest way to know this is to store this information
in a dictionary.
We'll use the name of the machine as the key
and the current users of that machine as the value.
So for each event we process, we'll
first check in the dictionary to see if the machine is already
there.
We need to check this because it could
be the first time we're processing
an event for that machine.
If it's not there, we'll create a new entry.
If it is, we'll update the existing entry
with the action corresponding to the event, which
means we either add the user if the event is a login
or remove the user if it's a logout.
Once we're done processing the events,
we'll want to print a report of the information we generated.
This is a completely separate task,
so it should be a separate function.
This function will receive the dictionary we generated
and print the report.
It's important to have separate functions to process the data
and to print the data to the screen.
This is because if we want to modify how the report is
printed, we know we only need to change the function in charge
of printing, or if we find a bug in how we're
processing the data, we only need to change the processing
function.
It would also allow us to use the same data-processing
function to generate a different kind of report,
like generating a PDF file, for example.
Yay, we know what we need to do, how we need to do it,
and how we'll structure our code.
Now we can get into the meaty stuff,
actually writing the code.
We've come a long way to get here, so let's
quickly rattle off what we know so far.
We know that we need to process the events to generate
a report.
We know how to sort the list of events chronologically.
We know that we'll store the data in a dictionary of sets,
which we'll use to keep track of who's logged in where,
and that we'll have a function that
generates the dictionary and a separate one that
prints the dictionary.
OK, I think that's everything.
Know what that means?
We're finally ready to write our code.
Here we go.
Let's start by defining the helper
function that we'll use to sort the list.
We'll use the simple function as the parameter
to the sort function to sort the list.
Now we're ready to start coding our processing function, which
we will call current_users.
The first step is to define the function.
Inside the function, we'll first sort our events
by using the sort method and passing the function we just
created as the key.
Now, before we start iterating through our list of events,
we need to create the dictionary where we will store the names
and users of a machine.
Now we're ready to iterate through our list of events.
Next, we want to check if the machine affected by this event
is in the dictionary.
If it's not, we'll add it with an empty set as the value.
Now, for the login events, we want
to add the user to the list, and for the logout events,
we want to remove users from the list.
To do this, we're going to use the add
and remove methods, which add and remove elements from a set.
Once we're done iterating through the list of events,
the dictionary will contain all machines
we've seen as keys with a set containing the current users
of the machines as the values.
This function returns the dictionary.
We'll handle printing in a different function.
Nice.
We now have the dictionary ready, and we need to print it.
For that, we'll create a new function
called generate_report.
In our report, we want to iterate over the keys
and values in the dictionary.
To do that, we'll use the method items.
That returns both the key and the value
for each pair in the dictionary.
Now, before we print anything, we
want to ensure that we don't print any machines where
nobody is currently logged in.
This could happen if a user logged in and then logged out.
To avoid that, we tell the computer only
to print when the set of users has more than zero elements.
Now, we said earlier that we want to print the machine
name followed by the users logged
in to the machine separated by commas.
Let's generate the string of logged
in users for that machine using the method join.
And now we can generate the string we
want using the format method.
Yay, we've written all the functions
we need to tackle our problem.
We're almost done solving our problem.
We've written the code that solves our problem
statement after following our research and plan.
We're now going to put all of our code in a Jupyter notebook,
execute it, and see what happens.
This is what our code currently looks like as we wrote it
in the previous video.
To check that our code is doing everything it's supposed to do,
we need an event class.
For this scenario, we'll use the very simple event class.
OK, we have an event class that has a constructor
and sets the necessary attributes.
Using this constructor, we'll create some events
and add them to a list.
OK, we've got a bunch of events.
They're currently unsorted.
They affect a few machines and include some users.
We'll feed these events into our function and see what happens.
Everything is now ready to go.
Drum roll, please.
[DRUM ROLL]
Great.
Our code correctly created a dictionary
with the machine names as keys.
There's one empty set and two sets with one value.
Let's now try generating the report.
Whoop whoop, success.
Our report correctly skipped the one machine
that had an empty set.
That's great.
You've made it through the first course,
but your journey with Python is just heating up.
In our next course, my friend and colleague Roger
is going to be your instructor as you
learn how Python interacts with the operating system.
You'll build on all the skills you learned here,
and your programming is going to get
a little more sophisticated.
Hey, Roger.
So what can learners expect from the next course?
ROGER: Hey, Christine, and hello to all the learners out there.
I'm super excited about the next course.
We're going to cover how to set up your own developer
environment in Python, and in no time,
you'll start feeling comfortable using code
to interact with the system.
We'll also manipulate files and processes
running on the OS and dive into regex,
which is a super powerful tool for processing text files.
You're even going to write a script that
might be similar to a task you'd be assigned at your job.
But personally, my favorite part the whole course
is definitely where we talk about the Linux OS,
and it's not because it's the primary OS I use in my job.
Linux opens up a whole world of customization
and configuration, and I find it really interesting.
We've got a lot of powerful and fun concepts coming up,
so don't miss out.
I'll see you over in the next course.
CHRISTINE: Thanks, Roger, and thank you, every one of you,
for tuning in and hanging with me in this course.
I'm not crying.
You're crying.
Bye for now.
SPEAKER: Congratulations on finishing
this lesson in the Google IT Automation
with Python Certificate.
Access the full experience, including job search help,
and get the official certificate by clicking the icon
or the link in the description.
Watch the next lesson in the course by clicking here,
and subscribe to our channel for more lessons