 In this video, we're going to learn how we can write our own modules that we can then import in JupyterLab. So, this video is a bit different in that we are going to use a new notebook file. So, let's rename it and call it local modules, because that's what they are called in the Python world. However, now we also have to do something else. So, to do that, let's create a new launcher by clicking on the plus here and go down here. And for now, let's go ahead and click on text file here to create a new text file. And now we are going to rename it into sample underscore module dot pi. We don't leave the txt for text file, but we rename it into dot pi. And so now what we are going to do is we are going to write our first Python module that is a file, a dot pi file that only contains Python code and then we can do something with it. For example, import it. Okay, so let's go ahead and first write a doc string. So, we remember doc strings from writing functions. However, we can also use doc strings to document what is the content inside a module. So, for example, let's write here utilities for finding statistics. Okay, that is a subject. And technically speaking, we could go ahead and simply write blah, blah, blah for further documentation. Okay, so that is a doc string just like a doc string for a function. But now this is at the beginning of a dot pi file and therefore we call it the module doc string. So, a doc pi file is also referred to as a module. So, let's continue. And now what you're going to do is we are going to write one function in there and that is going to be the function that we have already developed a couple of times in different variants throughout this video lectures. And it's the function that takes some list as an argument and then gives back the average of the even numbers in the list. Okay, so let's go ahead and define a function called average events. And it takes two parameters. So, the first one will be numbers. And the second one, and we put that behind the s-ricks here, we call scalar and give it a default value of one. So, we want to be able to scale the average after it has been calculated. Then we go ahead and write colon. And then comes the doc string for the function. So, let's write here, calculate the average of all even numbers. Let's go ahead and write a specify as the arcs section here, the parameters the function has. So, let's first write numbers. And in parentheses, we will mention that it's going to be a list of integers. And these are the whole numbers to be averaged. Let's then go ahead and also specify the second parameter here, scalar. Generically speaking, it should be a float or an int, but we can see a float as a generalization of an int in a way. And so, this is basically the number that multiplies the average. And now the function is going to return. So, returns the scaled average and that is going to be a float. So, let's quickly remember how we wrote the function. So, we are going to use a list comprehension. We are going to write n for n in numbers. If n, modulo divided by 2 has no rest. And this will create a new list object that lives only inside the function object as it is being executed. And we assign that to a local variable, which we call evens. And then in the next line, we go ahead and we will say average is the sum of the evens divided by the number of the even numbers, so the length of the evens list. And then in the last step, we are going to return the product of scalar times average. And now I go ahead and I simply say control S. And now I have defined a function object. For deductible purposes, I will simply go ahead and above the function, we will call the print function and we will simply write in there the text module is imported. And you will see in a bit why I do that. So, we will simply put that in. In a real world project, you would not do that, but this is just now the illustrator point. So, that is our first example in this course of a module that we created. And now let's go back to our notebook file. And on the left-hand side here, we see that here it is, we have the, let's maybe extend this a bit. We have the local modules.ipymb file here. And down here, we have the sample module.py file. So, see how both are in the same path. That is kind of important. And so, let's continue here. So, maybe you are interested in to know at some points in which path is my current notebook in. So, this is the so-called active path or the working directory, sometimes called. There is a utility that is called PWD, print working directory. And since this is not Python code, we have to start that with an exclamation mark, just like when we use pip. So, when I say PWD, this tells me the folder in which I am currently as I execute this file here. So, this is just in case that on your machine, when you try this out, you may, this may not work. And one of the most likely reasons for what I'm going to show you in a bit, it's not going to work on your machine is because either these files are in different folders or maybe they are in the same folder, but for whatever reason, the active working directory of the open notebook file is not the one where the file is in. But that's just to illustrate how we can look up the current directory. So, now, let's go ahead and just simply write import sample underscore module, which is the name of the sample underscore module dot py file. However, we are not going to write the dot py, so the dot py is basically will be added by Python automatically. And now, so that we don't have to type that much, we will simply go ahead and write we import that sample module as mod. Okay, let's execute this. And we see below the line here, it says module is imported. And usually, when you write a module, you don't want to have any code do something in the global level here in the global namespace. The only thing that you do in a module is usually you either define functions, you may also want to define a couple of constants, just like in the math module that we saw previously. But also, you may define some other things for most notably so-called classes, which we will look into in a later video, but usually code like this that is just executed, you don't usually put into a module. However, since we did, we see that once we import the module, this line here is simply executed. So, in other words, the code inside the dot py file inside the module is executed just as if we copy-pasted the code in here into a code cell. However, now note one important thing, if I go ahead and execute this cell again, we don't see the output again. And the reason is because Python for optimization purposes will not reload modules again a second time or a third time that it has already loaded in or imported. So in other words, if I now go ahead and I make any changes here in the dot py file here, I am not going to see them. Okay, so if for example I add three axes here and I save this file and I go back, I have no chance to get to these changes. So what I could do then is I could go ahead and I could say kernel, restart kernel and clear the outputs. And now go ahead and do it again. And now we see the access. So only the first time we execute or we import a certain module, it is actually executed. Okay, so that is a source of confusion for beginners. So let's go back and maybe simply get rid of this file here or this line here because this is really just for illustrating that the file, the dot py file is only executed once. Okay, now that we have executed the import statement and imported the module, what we can do is we can go ahead and call the built in help function and pass it the mod variable. And now we simply get a help message that is derived as we see from our module doc string. So here it says the name of the module is sample module, which is just the name of the file really. And then it says utilities for finding statistics. Right. And that is basically what we put into the subject line of the doc string and then under description, it says blah, blah, blah. So anything that comes after the first empty line will be put here in the help message. So that is how we can influence the help message. And then it says the function, there are functions defined and the function is shown here. The so-called signature is shown. So the parameters the function takes and so on. And also the entire function doc string is being shown here. And then lastly, the help message tells us in which file on my hard disk this code lives, so to say. Similarly, we could instead of using the help function, we could simply use the dir function. And this will give us a list of names that exist inside the module. And for now, we have always been ignoring the ones that start with double underscore. This is Python internals. But we see here that there is a thing called average events and technically speaking, at this point, we don't know what it is, but with the help message we just saw previously, we know that this is a function. So now what we could do is we could go ahead and say mod dot. So we use the dot operator, the attribute access operator and let's access the average events function. And let's simply go ahead for now, let's simply evaluate this so we can get a reference to this function. And we see that the function is in the sample module. And now what we could do is, of course, we can call the function as we called our own functions many times before. And let's now simply go ahead and create a new list object on the fly, which is 40, 41, 42, 43 and 44. We have seen this example before and we get back as the result, 42.0 just as we would expect. So when would you do that? So a best practice for me is that when I work in data science projects, I usually put all the code that I need or that I write and that I want to reuse in several notebook files. I put that into .py files. And then I package that code into like real .py files. And what we didn't see here in this example is you can also split your code across many, many .py files and make them dependent on each other that is called packaging. So you can organize your code in simply with simple .py files. It has a couple of advantages. First of all, let's maybe go to the GitHub page for this course. So if we go into chapter 02 functions, that's the chapter from which this content is taken. Here we see another file called sample module.py. And this has a bit more code in it and also longer description. But at the end of the day, this is a longer example of the same concept. And we see that in GitHub, GitHub already knows how to format everything correctly. So the text here, the doc string is formatted in one color and the pricing code is formatted in different colors and so on. So we can use tools like GitHub and also Git, of course, the utility to manage this here to organize .py files and to manage them. And that is a big advantage of putting code into .py files. And also we can now simply go ahead and create another module, another notebook file. Let's just keep it as untitled. And also here we could say import sample module. And then we can say sample module and, for example, also call the help function here. So we can reuse the same code from one file in several notebook files. And that is usually what you want to do. You never ever want to copy paste code from file to file. That is always the best practice. And whenever you find yourself copy pasting code, then usually there is a better way to do it. So therefore one thing to know is we use .py files to reuse code across several notebooks and also possibly across several projects. So maybe there is nothing that would prevent you from storing the .py files on some server, let's say GitHub for example. And then in different projects you can include your own code that you defined once. So that's the idea of a so-called local module. And again, this is nothing but a simple .py file that lives in the same folder than the notebook file. It could also live, of course, in a different folder, but then we would have to switch folders here in the notebook file. We're not going to do that here, but that is an easy example here of how we can modularize a code into .py files. So that is it for this video. Also the last video regarding chapter two in the book. And then we will continue with chapter three on conditional. So I see you soon.