====== Python modules, __name__ and "__main__" ====== Mithat Konar\\ Oct 21, 2022 ===== What's a module? ===== A module in Python is a file of Python code that is imported into another Python file. Importing modules gives you access to their contents in the file that imports them. A very popular module is the [[https://docs.python.org/3/library/math.html|math module]]. The most common way to import the code in the math module is to use the simplest form of the ''import'' statement: import math When you do this, you can use things that are made available to you in the module by prepending the name of the module and the dot operator in front of the identifier of the thing you want to use in the module: ang = deg * math.pi/180 val = math.sin(ang) ===== Writing your own modules ===== Any Python file you write can be imported into another Python file as a module. For example, let’s assume we have the file ''my_functions.py'' that contains some functions we use a lot: ''' file: my_functions.py Some functions that I use a lot. Mithat Konar ''' def triangle_area(base, height): ''' Return the area of a triangle of known base and height. Parameters: base: the base of the triangle height: the height of the triangle Precondition: base and height are numeric arguments. ''' area = base * height / 2 return area def rectangle_area(width, height): ''' Return the area of a rectangle of known width and height. Parameters: width: the width of the rectangle height: the height of the rectangle Precondition: width and height are numeric arguments. ''' area = width * height return area This can be imported into the file ''my_program.py'', which can then these use the functions defined in ''my_functions.py'': ''' file: my_program.py Interactive program that asks user to compute the area of a rectangle. Mithat Konar ''' import my_functions # Function definition(s) def say_hello(): '''Welcome the user to the program.''' greeting = 'This program will compute the area of a rectangle.' print(greeting) # "__main__" say_hello() # get data from the user w = float(input('Enter the width of a rectangle: ')) h = float(input('Enter the height of a rectangle: ')) # compute results area = my_functions.rectangle_area(w, h) # output results print(f'The area of a {w} by {h} rectangle is {area}.') Notice that to import the file ''my_functions.py'', **we used the name of the file //without// the .py extension**: import my_functions Notice also that we prepended the name of the module and the dot operator to the name of the function we wanted to access: area = my_functions.rectangle_area(w, h) ==== Where do you put the files you want to import? ==== There are a few places Python will look for files to import. The easiest place to put them for now is in the same directory (i.e., folder) as the file that will be importing them. ===== What’s in a __name__? ===== Every Python file that’s used in a program has a ''%%__name__%%'' variable associated with it. When a file is imported as a module, the file’s ''%%__name__%%'' variable is automatically set to a string containing the name of the module. So, in the example above, the ''%%__name__%%'' variable of the ''%%my_functions%%'' module while when it's imported into our program is ''%%'my_functions'%%''. However, when the file is //not// imported as a module, which is to say when a file is run as a program, its ''%%__name__%%'' variable is instead set to the somewhat cryptic string ''%%'__main__'%%''. This is done so that at runtime we can determine whether a file is being imported as a module or is being run as a program. If a file is being run as a program, the condition: __name__ == '__main__' will be ''True''. If the file is being imported as module, it will be ''False''. ===== Leveraging the __name__ variable ===== Because you are able to tell at runtime whether a file is being imported as a module or being run as a program, you can include additional code in the file you plan to use as a module that you only want to execute when run as a program. A common use for this is to include code that tests just the code in the module. In other words, you can use this feature to develop your module as a standalone program that includes code that tests the functions you are developing. But when you import the file as a module, those tests will not run. Adding some testing code to our ''my_functions.py'' file would like: ''' file: my_functions.py Some functions that I use a lot. Mithat Konar ''' def triangle_area(base, height): ''' Return the area of a triangle of known base and height. Parameters: base: the base of the triangle height: the height of the triangle Precondition: base and height are numeric arguments. ''' area = base * height / 2 return area def rectangle_area(width, height): ''' Return the area of a rectangle of known width and height. Parameters: width: the width of the rectangle height: the height of the rectangle Precondition: width and height are numeric arguments. ''' area = width * height return area if __name__ == '__main__': # test my functions print('Testing triangle_area:') b = 1 h = 1 area = triangle_area(b, h) print(area) b = 3.3 h = 2.2 area = triangle_area(b, h) print(area) print('Testing rectangle_area:') h = 1 w = 1 area = rectangle_area(h, w) print(area) h = 3.3 w = 2.2 area = rectangle_area(h, w) print(area) Notice the line: if __name__ == '__main__': This essentially says, “If this file is being run as a program, execute the code below. Otherwise, don’t.” So, this means when we ''import'' the file into ''my_program.py'', the testing code we added to ''my_functions.py'' won’t run. ===== Checking all your files ===== It’s a common practice that verges on being a best practice to add the if __name__ == '__main__': test to //all// Python files, even those you don’t plan to use as modules. So, for completeness, here is our original ''my_program.py'' file with the added test in the expected place: ''' file: my_program.py Interactive program that asks user to compute the area of a rectangle. Mithat Konar ''' import my_functions # Function definitions def say_hello(): '''Welcome the user to the program.''' greeting = 'This program will compute the area of a rectangle.' print(greeting) # "__main__" if __name__ == '__main__': say_hello() # get data from the user w = float(input('Enter the width of a rectangle: ')) h = float(input('Enter the height of a rectangle: ')) # compute results area = my_functions.rectangle_area(w, h) # output results print(f'The area of a {w} by {h} rectangle is {area}.')