Due: , 11:59 pm
The goals of this week's project are to get further experience with modules and hierarchical design, and to expand your ability to communicate between a Python program and the Terminal.
In particular, we will be exploring the ability to pass information from the Terminal to a program when you execute the program. This is called using command-line arguments for a program. The concept is similar to passing arguments to a function in Python, except that you do this in the Terminal when you run a program.
If you have not already done so, mount your personal space, create a new project4 folder, and bring up TextWrangler and a Terminal.
Create a new file com.py. Put your name, date, and the class in a comment block at the
top (as usual), then
import sys. Then put the following line of code in your
file, save the file, and run it.
What does it do? Run it again, but this time try typing some random things on the command line after python com.py.
What is contained in the variable sys.argv? What data type are the elements of sys.argv? How could we make use of that?
From your experimentation, you should see that the variable sys.argv is a list of strings--it contains the strings you typed in on the command line. That means we can use sys.argv to bring information from the command line into a python program, which can be very useful for our programs.
With this, as in other aspects of programming, we need to pay attention to the type of data we're dealing with. As an illustration, add the following to com.py.
print(sys.argv + sys.argv)
Then run the program again as
python3 com.py 1 2. What do you think will happen? Did the program do what you expected?
Now, add another line to your program where you cast sys.argv and sys.argv to integers before adding them together, and then run your program again. Did it do what you expected that time?
What happens if you run your program as just
When you write any program that expects command line arguments, it is very important to check to see if the user actually provided them. This is part of error-checking, which is essential for writing useful programs. If your program expects two arguments, then it needs to check that the user provided at least two arguments. If they didn't, it's common courtesy to give the user a helpful reminder of the arguments that the program expects. That reminder is called a usage statement.
We can always check how many command line arguments there are by looking at the length of sys.argv. At the beginning of your active code, test if the length of sys.argv is less than three (the name of the program plus two arguments). If the user did not provide enough arguments, then print out a usage statement and exit. A usage statement generally looks something like the following.
Usage: python3 com.py <number> <number>
To exit a Python program, just use the function exit().
To see examples of real usage statements, go to the terminal and type cp or mv with no arguments.
When you are using command-line arguments in your own programs, be sure to use a structure like the following:
import sys def main(argv): # usage statement here # cast the command line strings to the appropriate type and assign # them to local variables # main code here return if __name__ == "__main__": main(sys.argv)
If you follow the above structure, then the only place you will use the sys.argv variable is when you call your main function. Inside your main function, it sees only a list of strings (argv). The usage statement checks the list of strings to see if there are enough, and the next section of code does the necessary casting to set up local variables--with informative names--to hold the command line parameters. This structure follows the concept of modular design: all relevant variables enter a function as parameters.
Rewrite com.py to use the above structure. Run it and verify that it continues to function properly.
Note that many command line programs use flags as part of their command-line parameters. For example, if you run the command ls with the flag -l then it lists many attributes of the files in a directory. Other flags take numbers or strings after the flag to indicate a value (such as ones you've used with the cut command!). Often, the flags themselves are optional, and the program has to figure out what flags are given on the command line and then grab any values associated with those flags. This process of parsing command-line strings is a standard task that many programs do. There are packages for assisting in that task, or you can write your own code that loops over the components of command-line strings and figures out what is there. You don't need to do anything this complex for this project, but it is an extension if you want to try it.
Create a for loop that loops 10 times. Each time through the loop have it print the result of calling random.random(). Then run your program. It should generate 10 numbers from a uniform random distribution between 0 and 1. Running the program again should generate 10 different numbers.
You can create many different kinds of random numbers using the random package. For example, if you want integers randomly distributed between 0 and 100, inclusive, use the randint() method of the random package. Using the function random.randint(0,100) will generate numbers in the range 0 to 100, inclusive (i.e., including the bounds 0 and 100).
You can also create numbers following a Gaussian distribution (also called a normal distribution) using the random.gauss function, which takes two arguments: the mean and standard deviation. Try modifying your program to generate different types of random numbers and see what happens.
When you are done with the lab exercises, you may start on the rest of the project.
© 2019 Eric Aaron (with contributions from Colby CS colleagues).