Fork/Clone Ch.13 Libraries/Modules Jedi Training
Fork/Clone Ch.13 Libraries/Modules Jedi Training
A library is a collection of code for functions and classes. Often, these libraries are written by someone else and brought into the project so that the programmer does not have to “reinvent the wheel.” In Python the term used to describe a library of code is module.
By using import arcade and import random, the programs created so far have already used modules. A library can be made up of multiple modules that can be imported. Often a library only has one module, so these words can sometimes be used interchangeably.
Modules are often organized into groups of similar functionality. In this class programs have already used functions from the math module, the random module, and the arcade library. Modules can be organized so that individual modules contain other modules. For example, the arcade module contains submodules for arcade.key, and arcade.color.
Modules are not loaded unless the program asks them to. This saves time and computer memory. This chapter shows how to create a module, and how to import and use that module.
There are three major reasons for a programmer to create his or her own libraries:
It breaks the code into smaller, easier to use parts.
It allows multiple people to work on a program at the same time.
The code written can be easily shared with other programmers.
Many programs can get rather long. By separating a large program into several smaller programs, it is easier to manage the code.
If multiple programmers work on the same project, it is nearly impossible to do so if all the code is in one file. However, by breaking the program into multiple pieces, it becomes easier. One programmer could work on developing an "Sith" sprite class. Another programmer could work on the "Droid" sprite class. Since the sprites are in separate files, the programmers do not run into conflict.
In this example we will break apart a short program into multiple files. Here we have a function in a file named test.py, and a call to that function:
def yoda():
print("Smart, you are!")
def main():
yoda()
if __name__=="__main__":
main()
This program is probably not long enough to earn it's very own file, but if both the function and the main program code were long, it would be different. If we had several functions, each 100 lines long, it would be time consuming to manage that large of a file. But for this example we will keep the code short for clarity.
We can move the yoda function out of this file. Then this file would be left with only the main program code. (In this example there is no reason to separate them, aside from learning how to do so.)
To do this, create a new file and copy the yoda function into it. Save the new file with the name my_functions.py. The file must be saved to the same directory as test.py.
# my_functions.py
def yoda():
print("Smart, you are!")
# test.py
def main():
yoda()
if __name__=="__main__":
main()
Unfortunately it isn't as simple as this. The file test.py does not know to go and look at the my_functions.py file and import it. We have to add the command to import it. You do this by using the word import and then the namespace of the module. Don't import my_functions.py, just import my_functions.
# test.py
import my_functions
def main():
yoda()
if __name__=="__main__":
main()
That still doesn't work. What are we missing? Just like when we import random or math, we have to put the package name in front of the function. The following will work because my_functions. is prepended to the function call.
# test.py
import my_functions
def main():
my_functions.yoda()
if __name__=="__main__":
main()
Prepending the namespace to the function call helps avoid name collisions. For example, we might import another library called other_functions. What if both libraries had a yoda function? Putting the namespace in front of the function call, specifies which yoda function we need.
# test.py
import my_functions
import other_functions
def main():
my_functions.yoda()
other_functions.yoda()
if __name__=="__main__":
main()
But what if you don't have name collisions? Typing in a namespace each and every time can be tiresome. You can get around this by importing the library into the local namespace. The local namespace is a list of functions, variables, and classes that you don't have to prepend with a namespace. Let's remove the original import and replace it with a new type of import:
# test.py
from my_functions import *
def main():
yoda()
if __name__=="__main__":
main()
This works even without my_functions prepended to the function call. The asterisk is a wildcard that will import all functions from my_functions. A programmer could import individual ones if desired by specifying the function name.
Whenever a Python file is run, a special global variable called __name__ is created. This is the word name with 2 underscores before and after it. If a file is your main program and being run directly, the interpreter sets __name__= "__main__". If, however, the file is being imported as a module, the __name__ variable is set to the namespace of the file.
Let's see how this works in our my_functions.py and our test.py files. Change the files to look like the following:
# my_functions.py
def yoda():
print("Smart, you are!")
print("The __name__ variable is :",__name__)
if __name__ == "__main__":
print ("my_functions is being run directly")
else:
print ("my_functions is being imported")
# test.py
from my_functions import *
def main():
yoda()
main()
print("The __name__ variable is :",__name__)
if __name__ == "__main__":
print ("test is being run directly")
else:
print ("test is being imported")
Now if we run my_functions.py directly we will see the following output:
The __name__ variable is : __main__
my_functions is being run directly
And if we run test.py directly we will see the following output:
The __name__ variable is : my_functions
my_functions is being imported
Smart, you are!
The __name__ variable is : __main__
test is being run directly
As seen above, when my_functions.py is run directly, the __name__ variable is set to "__main__" and when it is run through test.py by importing, the __name__ variable is set to the namespace of the file, i.e. my_functions.
We will continue to use if __name__ == “__main__”: to execute our code only if the file was run directly, and not imported. It is not actually necessary to do this in Python (so you might think this was a big waste of time) but it is in other languages, which is why we are introducing it here. If you want to be professional at your programming you might as well start practicing proper protocols. So our two original files should actually look like the following:
# my_functions.py
def yoda():
print("Smart, you are!")
# test.py
from my_functions import *
def main():
yoda()
if __name__ == "__main__":
main()
Now that we've talked about Classes, Objects and Modules we might have a better understanding of our school's LMS (Learning Management System) called Canvas. Before Canvas we had a similar LMS called Moodle. Moodle is actually written in PHP but the syntax is very similar to Python. Moodle and Canvas both contain lots of Libraries (Modules) such as the Quiz Module, Forums Module and the Progress Bar Module. In these modules are classes from which any teacher through the GUI (Graphic User Interface) can call an instance (object) on their course home page. A teacher might have three checklist objects or a teacher might have four instances of a forum. Now perhaps you have a better understanding of the acronym, MOODLE.