Modules
Note
Be sure to change directories to your python_class folder before running Python or starting the Python REPL.
Remember: if you are using Windows, you may need to type py or py -3 instead of python to start Python or run a Python program.
An Expected Failure
Let’s try something new that we’ve never done before and don’t yet know how to do.
Copy-paste this code into a file called grade.py (either overwrite your existing grade.py program or make a new file with a different name):
import sys
arguments = sys.argv
percent = arguments[0]
if percent >= 90:
print('A')
elif percent >= 80:
print('B')
elif percent >= 70:
print('C')
elif percent >= 60:
print('D')
else:
print('F')
This program is meant to read a command-line argument that represents a percentage grade and then it will print out the letter grade that the given percentage represents.
The program is broken. Try to poke around in this code and see what we can find that appears to be broken.
What’s a Module?
A Python “module” is a file that contains Python commands.
These files end with the extension .py.
Python modules are used for two different purposes:
Creating standalone programs (sometimes called “scripts”) that can be run with inputs (command-line arguments)
Creating useful helper code for other Python modules to use
Command-Line Script
We’ve typed all of our code at the REPL up to now. Let’s save our code in a file and make a command-line script.
Note
Python does not like tab characters!
If you are using Notepad++, you need to change the setting to use spaces instead of the tab character.
Go to Settings -> Preferences, then click on Language in the left column.
Check the box in the lower right to use spaces instead of tabs.
Set it to 4 spaces.
Open your favorite code editor and create a file called greetings.py in your python_class folder which contains the following code:
print("Hello world!")
Once we’ve saved our file, we can go to our terminal window, and run:
$ python greetings.py
Hello world!
We’ve just made our first Python program!
Importing Modules
We can also import .py files to use them as modules.
Let’s open the Python REPL and import the file we just created (note we don’t include the ".py" when importing)
What do you think will happen when we import this module?
>>> import greetings
Will we see anything printed to the screen?
Or will we see nothing right after importing?
>>> import greetings
Hello world!
That’s weird. We saw “Hello world!” printed out just from importing this module.
When we import a module, Python executes all code in the imported module.
Our module has a side effect.
Normally a .py file will either be a Python program which has side effects (like printing) is meant to be run from the command-line or it’ll be a module that defines variables, functions, and classes but has no import side effects.
Note
Our module should never do anything noticeable at import-time. It should only do things when we ask it to. But when a module is imported, Python executes all code in the module, so our greeting was printed. We need a way to prevent this from happening.
To avoid having our module print “Hello world” on import, we can check the __name__ variable on import.
Note that there are two underscores before and after the variable name.
These types of variables are often called “magic” variables or “dunder” variables.
As a verbal shorthand, we will say “dunder name” to mean “double underscore name double underscore”.
Let’s change our code to this:
greeting = "Hello world!"
if __name__ == "__main__":
print(greeting)
When we run a file as a program from a command line, __name__ is always "__main__", but when it is imported, __name__ is equal to the name of the module, in this case "greetings".
Let’s call our script again and make sure it still works:
$ python3 greetings.py
Hello world!
But if we opened up a Python REPL again and imported this program, we’d see nothing printed out.
Namespaces
Let’s make a Python module that doesn’t have any import side effects.
Create a file named constants.py and put your name and your favorite number in it:
name = "Trey"
favorite_number = 3.14159265358979
Now open up a Python REPL and import contants:
>>> import constants
Now that your module has been imported, what happens if you type look at either the name or favorite_number variables?
>>> name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'name' is not defined
>>> favorite_number
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'favorite_number' is not defined
We don’t have access to these variables! Why not?
When importing a module, you don’t get instant access to those variables. When you import a module, Python creates a namespace for that module automatically. A namespace is an object that variables live on.
When we import this constants module, Python makes a single object representing the entire module:
>>> import constants
>>> constants
<module 'constants'>
>>> constants.name
'Trey'
Note that in order to display the value of the variable name, we have to prepend the module name (with a . in between them).
This is because the variable name belongs to the namespace of the module it is contained in (constant).
If we wanted to avoid having to type constants.name everywhere we we need to refer to our name, we could use a special from X import Y syntax:
>>> from constants import name
>>> name
'Trey'
We can only access name (but not favorite_number) because we’ve only imported that one variable from the constants module.
Import Cheat Sheet
Here are the various ways to import things:
import some_module
some_module.some_function()
some_module.another_function()
from some_module import some_function, another_function
some_function()
another_function()
import some_module as m
m.some_function()
m.another_function()
from some_module import some_function as f1, another_function as f2
f1()
f2()
Command-Line Arguments
Let’s change our greetings.py program so that it can accept command-line arguments.
First, what do you think will happen if we pass command-line arguments to our program right now?
$ python3 greetings.py Trey
Hello world!
Strangely Python accepts any arguments we give to it by default. It’s our job to take any arguments given to Python and make use of them.
We need to import the sys module to find the command-line arguments given to the running Python process.
The sys module is module in Python’s “standard library”, meaning it comes bundled with Python.
In the sys module there’s an argv variable which points to a list where the first element is the name of our script and all subsequent elements are the arguments given on the command line.
We will discuss lists more later in the class; for now just know that list elements are designated by square brackets, [], and lists use zero-based indexing, so that [0] is the first element of a list and [1] is the second element.
Let’s modify our script to use sys.argv to print out the first command-line argument:
import sys
print(f"Hello {sys.argv[1]}!")
Now we can pass arguments to our script:
$ python3 greetings.py world
Hello world!
$ python3 greetings.py earthlings
Hello earthlings!
But what happens when someone tries to run our program and forgets to put the argument?
$ python3 greetings.py
Traceback (most recent call last):
File "greetings.py", line 4, in <module>
print(f"Hello {sys.argv[1]}!")
IndexError: list index out of range
This is not very friendly! Let’s change our program to check for this.
We want to make sure that the script has more than just the first element in the sys.argv variable.
To do this we can use the built-in len function to check the length of sys.argv and make sure it is greater than 1.
import sys
if len(sys.argv) > 1
print(f"Hello {sys.argv[1]}!")
else:
print("Greetings, my absent-minded friend!")
Now when we run it without arguments, we won’t see an exception:
$ python3 greetings.py
Greetings, my absent-minded friend!
$ python3 greetings.py Pete
Hello Pete!
Module Exercises
Hint
If you get stuck for a minute or more, try searching Google or using help.
If you’re stuck for more than a few minutes, some of these links might be helpful for some of the exercises below:
Howdy
File: Create a file howdy.py in the modules sub-directory of the exercises directory.
Test: Run python test.py howdy.py from your exercises directory.
Exercise: Make a program howdy.py that prompts the user for their name and then prints Howdy <NAME>! where <NAME> is the user’s name.
$ cd modules
$ python howdy.py
What's your name? Trey
Howdy Trey!
The first line should prompt for input unchanged, and the second line should be the greeting with the user’s name.
Hint
You can get user input with the input() function. Don’t forget the exclamation mark and be mindful of spaces and capitalization.
Temperature Feedback
File: Create a file temp.py in the modules sub-directory of the exercises directory.
Test: Run python test.py temp.py from your exercises directory.
Exercise: Make a program temp.py that takes a temperature in Fahrenheit and prints “Too hot” if the temperature is above 80, “Too cold” if the temperature is below 65, and “Quite nice” if the temperature is between 65 and 80. You can assume the temperature is a positive two-digit number.
$ cd modules
$ python temp.py 80
Quite nice
$ python temp.py 82
Too hot
$ python temp.py 60
Too cold
$ python temp.py 70
Quite nice
Dollars
File: Create a file dollars.py in the modules sub-directory of the exercises directory.
Test: Run python test.py dollars.py from your exercises directory.
Exercise: Make a program dollars.py that takes a number and returns that number written as US dollars with cents. See examples below.
$ cd modules
$ python dollars.py 80
$80.00
$ python dollars.py 5.5
$5.50
$ python dollars.py 3.048
$3.05
$ python dollars.py .05
$0.05
Hint
You’ll want to use Google for this one. You can use the string format method or f-strings.
Add
File: Create a file add.py in the modules sub-directory of the exercises directory.
Test: Run python test.py add.py from your exercises directory.
Exercise: Make a program add.py that takes two numbers and prints out the sum of these numbers. To run it without using the test framework:
$ cd modules
$ python add.py 3 5.2
8.2
$ python add.py -7 2
-5.0
$ python add.py -2 -1
-3.0
Mad Libs
File: Create a file madlib.py in the modules sub-directory of the exercises directory.
Test: Run python test.py madlib.py from your exercises directory.
Exercise: Create a program madlib.py that creates a phrasal template word game (Mad Libs). Your program should repeatedly prompt the user to enter words within different categories (noun, verb, adjective, etc.), then print out these words within one or more sentences.
Here’s an example:
$ cd modules
$ python madlib.py
Enter a verb: skip
Enter an adverb: merrily
Enter an adjective: mysterious
Enter a noun: dragon
Enter an adjective: purple
To write a Python program, you must first skip on your computer.
Then you'll merrily write some code.
Your code must be mysterious or Python will show you a dragon when you run it.
That's why Python is purple!
For your program to pass the tests, you must:
Prompt the user for at least 3 words using
input()Print out 1 or more sentences that use all of the given words
Focus on getting your program working first, then make it entertaining!
Hint
Use the input() function to prompt for user input and f-strings or string concatenation to build your sentences.
Difference Between
File: Create a file difference.py in the modules sub-directory of the exercises directory.
Test: Run python test.py difference.py from your exercises directory.
Exercise: Make a program difference.py that takes two numbers and prints the positive difference between these two numbers. To run it without using the test framework:
$ cd modules
$ python difference.py 3 5
2.0
$ python difference.py 6 3.5
2.5
$ python difference.py -7 2
9.0
Silly Case
File: Create a file silly.py in the modules sub-directory of the exercises directory.
Test: Run python test.py silly.py from your exercises directory.
Exercise: Make a program silly.py that takes a string and returns a “silly case” string. A “silly case” string is a string which has the first letter of each word lowercased and every letter after it uppercased.
$ cd modules
$ python silly.py 'hello world!'
hELLO wORLD!
$ python silly.py 'Hiya world'
hIYA wORLD
$ python silly.py HEY.
hEY.
Hint
You’ll want to look through the methods that exist on strings for this one.
Allow Zero Arguments
File: Create a file greetings.py in the modules sub-directory of the exercises directory.
Test: Run python test.py greetings.py from your exercises directory.
Exercise: Make a script like our greetings.py file example above, but allow it to take one or zero arguments. When one argument is given, it should print out “Hello <name>!” and when no arguments are given, it should say “Hello world!”. To run it without using the test framework:
$ cd modules
$ python greetings.py Trey
Hello Trey!
$ python greetings.py
Hello world!
Remember to move back to the exercises directory before running the test framework test!
$ cd ..
$ python test.py greetings.py
Testing greetings.py
..x
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK (expected failures=1)
CLI Only
File: Create a file hello.py in the modules sub-directory of the exercises directory.
Test: Run python test.py hello.py from your exercises directory.
Exercise: Make a module hello.py that prints “Hello world!” when you use it from the command-line, but prints an error message when you try to import it. To run it without using the test framework:
$ cd modules
$ python hello.py
Hello world!
Open the Python REPL and import the module:
>>> import hello
Error: This module can only be run from the command-line
Allow Unlimited Arguments
File: Edit the file greetings.py in the modules sub-directory of the exercises directory.
Test: Run python test.py greetings.py from your exercises directory.
Note
To run tests for this updated program, open modules_test.py, find the line that starts with class GreetingsTests. Look for the test named test_with_multiple_arguments and comment out the @unittest.skip line just above it. That line tells the Test Framework we don’t expect the test to pass, but now we are changing the program so the test should pass, therefore we comment the line out.
Exercise: Modify the greetings.py program so that it takes any number of arguments. All arguments should be joined together by spaces and printed out. To run it without using the test framework:
$ cd modules
$ python greetings.py
Hello world!
$ python greetings.py Kirk
Hello Kirk!
$ python greetings.py from planet Earth
Hello from planet Earth!
Tip
You may have noticed we did this in an example earlier, but you can get a list of all arguments with sys.argv[1:]. We’ll explain how this works in the next class.
Hint
Use str.join on the sys.argv list.