Computer science is about solving problems, preferably in a beautiful and artistic way. Computers are used in every discipline from medicine (medical robotics, analysis of the spread of disease, design of drugs) to the visual arts – I’m sure you’ve seen a Pixar film recently. Computer science is one of the newest disciplines; it has completely transformed our world and will continue to do so.
Above all else, computer science is a creative discipline, mixing some of the best aspects of engineering, art, science, language, and mathematics. Learning about computation will change how you view problems in every discipline, and how you think about solutions to those problems.
Python shares many similarities with other programming languages, including Java and C++, and once you’ve learned Python, these other languages will not be difficult to pick up. Python is a fairly popular language, and it’s also fairly easy to get started with.
Let’s get started. A computer program is made up of instructions that a computer follows. Here is a simple program with one instruction:
This program causes the computer to print the word Hello
in the console window. Notice that the quotation marks around
Hello
are not printed.
Here’s another program:
In this multi-line program, commands are executed in the order they appear.
As the Python interpreter runs a program, the interpreter keeps track of the line number that is currently being executed. The bookmark used to keep track of the line number is called the program counter.
The program counter always starts out pointing at the first line of the code in the program you run. It executes that line of code. Depending on what that line of code says, one of two things happens:
Why would we ever want the interpreter to suddenly jump to a new line of code? We’ll see many reasons, but the first is to write and use our own commands, called functions, that are made up of a chunk of lines of code.
By giving a name to a chunk of lines of code, we can easily re-use
that section of code without having to retype all those lines every
time. Here’s a program that defines our own two functions,
say_hello
and why_goodbye
.
Notice that nothing is printed when you run this program. We have instructed Python that there are two functions, and described them, but have not actually instructed Python to run either of the functions.
Function definitions have two parts: a header, and a body. The header gives the name of the function you want to define (as well as some other things we’ll see later). The body is a set of lines of code that tell what the function does. Each line of the body must be indented by pressing the tab key. The indentations tell Python where the function body begins and ends.
The header uses the keyword def
(short for
define), the name of the function you’d like to define, parentheses
after the name of the function, and a colon. So the header for the first
function is:
def say_hello():
The body of the first function is
print("Hello.")
To tell the interpreter to actually run the body of a function, you use a function call. To write a function call, write the name of the function followed by parentheses.
When the program counter reaches a function call, the interpreter takes a note of where the program counter is, moves the program counter to the first line of the body of the appropriate function definition, and executes the lines of code in the function. When the interpreter gets to the end of the body of the function, the program counter jumps back to just past the function call, and Python continues from there.
Let’s trace out the program counter’s locations as the above program executes:
say_hello()
.say_hello
is called.say_hello
, which is print("hello")
This line causes hello
to be printed.say_hello
, and so it jumps back to just past the call of
say_hello
, which is the line containing the second call of
say_hello
.say_hello
, which is print("hello")
This line causes hello
to be printed.say_hello
, and so it jumps back to just past the second
call of say_hello
, which is the line containing the call of
why_goodbye
.why_goodbye
, which is
print "I don't know why you say goodbye."
This line causes
I don't know why you say goodbye.
to be printed.why_goodbye
, and jumps back to the line containing the call
`print(“I say hello.”)I say hello.
is printed. But this call to
print
was the last line in the Python program, and so the
program terminates.It is very important to understand the order in which Python executes lines of code. Stepping through code one line at a time in your mind in the order that Python executes those lines is a very good habit to get into.
Objective: Write and call your own functions to learn how the program counter steps through code.
You will write a program that introduces you and prints your favorite number.
print_favorite_number
print_favorite_number
.say_introduction
that prints
Hello, my name is X.
and I am a Y.
on two
separate lines, where X and Y are replaced by whatever you like.say_introduction
so that the
introduction is printed before the favorite number.Test your code after steps 2 and 4: take a minute to think through what you expect to happen, and then press the run button.
Here is a solution. No peeking until you have solved it yourself!
Building higher-level concepts from simpler pieces, and then working with those higher-level concepts, is called abstraction. Abstraction is a major tool in computer science that we’ll come back to over and over.
Abstraction hides the details of how things work. Functions are our first example of abstraction. We defined a few functions, each in terms of a sequence of simpler commands. Once we defined those functions, we were able to just use them without thinking (too much) about how they worked.
Abstraction is not just important in computer science. When I press the gas pedal on my car, a lot of stuff happens, but because I have the higher level “push-gas-pedal” concept, I don’t have to think about the details of what is going on in the internal combustion engine to make my car go.
It might be fun to consider any other hobby or academic discipline you are interested in and explicitly identify the uses of abstraction, and levels of abstraction.
Here’s another big win for functions. You can use a function someone else wrote, without knowing exactly the internal details of the function. Let’s look at an example:
The first line says that this program will use the
print_date_and_time
function from the
simplefunctions
library of functions. (In Python, such a
library is called a module.) The program then calls the
print_date_and_time
function. When this function is called,
the interpreter saves the current value of the program counter, sets the
program counter to the beginning of the print_date_and_time function
somewhere in the simplefunctions
module, executes the code
it finds there, and then resets the program counter to the original,
saved value.
Just like the print command, functions can take parameters – additional information that influences the results of calling the function.
When making a function call, we write the values of the parameters inside the parentheses. We say that we pass the parameters to the function at the point of call. Functions may take multiple parameters, in which case we separate them by commas when we call the function. Here’s an example:
There are a few things to notice. First, there’s the
import
command. This first line says “go to the
cs1lib_web
module; we’ll be using the clear
,
draw_circle
, and start_graphics
functions from
there.”
Then we define the draw
function. This function isn’t
executed quite yet; we are just defining it. Python doesn’t even look
inside the function body yet. Instead, Python jumps to the line
start_graphics
.
The function call start_graphics
does two things:
start_graphics
.We never actually have to call the function draw
ourselves in this case. Instead, we passed the name of this function as
a parameter to start_graphics
, and that function runs
draw
. Yes, the parameter that we pass to
start_graphics
is not a number, but rather a function.
start_graphics
expects to be given a function as a
parameter.
What do we know about start_graphics
? We know that it
enables us to do graphics by opening a window on which graphics appear,
and we know that it runs a function that we pass to it as a parameter.
We don’t know how it does what it does, however. Abstraction at
work!
Let’s look at what happens when start_graphics
gets
around to calling draw
. First, draw
calls the
function clear
, which clears the window.
Second, draw
calls the function
draw_circle
, passing it three parameters. The first
parameter, 125, says to draw the circle at x coordinate 125 in
the window. The second parameter, 100, says to use the y
coordinate 100. The third parameter, 50, says that the radius of the
circle should be 50. The final line of the draw
function
calls the draw_circle
function again, with different
parameters.
It is very important to understand the order in which Python
executes lines of code. Here is an exercise. Grab an index card or
piece of paper, and place it under the first line of code in the
program. Move the card in the same way the program counter would move.
First, the import statement. Then, the line def draw
. After
that, jump past the body of the draw
function, since this
is just the definition of the function. Jump all the way down to
start_graphics
. We know that this function calls
draw
. So eventually, we jump back up to the first line of
the body of draw
, and step through the lines in
draw
.
Stepping through code one line at a time in the order that Python executes those lines is not very exciting, but a good habit to get into. You should step through every piece of code you see as you are learning Python.
We glossed over what the coordinates passed to the
draw_circle
functions really mean. When we open a window
for graphics, there’s a coordinate system within the window. Coordinates
correspond to pixels in the window, with (0, 0) at the upper left corner
of the window:
The coordinates (125, 100) mean the pixel that is 125 pixels to the right and 100 pixels below the upper left corner. The above diagram shows a rectangle with a black outline one pixel thick and a red fill, with its upper left corner at (3, 1) and its lower right corner at (9, 5).
Think of it this way: starting from the upper left corner of the graphics window, x coordinates increase to the right, and y coordinates increase down from the top. If you think about how x and y coordinates usually work in mathematics, graphics on a computer doesn’t quite match up. The x direction works, but in math, increasing y coordinates go up, whereas in computer graphics, increasing y coordinates go down.
What do the parameters passed to draw_circle
mean? The
first two parameters give the x and y coordinates of
the circle’s center, and the third coordinate gives the circle’s radius
in pixels. Here’s a simple exercise for you to try: What would you see
if you called draw_circle(0, 0, 100)
?
Objective: learn how to call drawing library functions that take parameters, in order to draw a desired complex picture.
Write a program that causes a yellow smiley face to be drawn on the screen. You have a 200 by 200 window available.
Draw the outline of the face. Put your code for drawing the
outline after the line # draw the outline of the face
.
(Lines that begin with #
are ignored by the computer, and
are for human readers only.
Draw the eyes. Put your code for drawing the eyes after the line
# draw the eyes
.
Bonus challenge. Draw the mouth. Hint – draw a circle, and then erase the top part of it by drawing some sort of yellow shape.
Here is a solution. No peeking until you have solved it yourself!
Computer programs are not just for computers. Good code should do two things:
A well-written program is more than a machine for solving a problem – it is in a real sense a description of a solution to a problem. How to write good, human-readable code is a major focus of this course, and we’ll come back to it again and again.
Let’s look at the following bad program.
What does this program do? Does it describe how to solve a problem? What’s the problem? Is this is a good solution? Could you modify it easily to solve a more interesting problem, without even knowing what the program does?
In this case, the program is short and you could figure out what it does by running it with Python. It would still be a lot of work to figure out what each line of code was intended to do, although we might get a high-level picture from Python.
(One sidenote: from cs1lib import *
tells Python that
you want to be able to use every function from the cs1lib
module, freeing us from having to specify each and every function we
intend to use.)
You can use the #
symbol in Python code to indicate code
that Python should ignore. On a line of code, everything after the pound
symbol is called a comment, and is ignored by Python – it’s
just there for human readers.
We can now see exactly what the program is intended to do, and also which lines of code accomplish which parts of the solution.
How much should you comment your own code? Here are some guidelines:
Good comments add new information, but that does not mean you should comment every single line of code. Here’s a distracting comment that is not useful:
draw_rectangle(280, 310, 25, 40) # draw a rectangle
We can see from the function name that this line draws a rectangle. A more useful comment would tell us what we are trying to do with the rectangle (in this case, draw a door). Another comment might tell us the fill color:
# draw the door
set_fill_color(.6, .5, .3) # light brown
draw_rectangle(280, 310, 25, 40)
Organizing code into function definitions and function calls is an
example of abstraction, and also is an example of good style. It’s
probably not hard to guess that the function draw_rectangle
draws a rectangle. We could have drawn the rectangle by drawing four
individual lines using four function calls, but it’s better style to use
a single, appropriately specific function call.
In the previous example, we saw a few new graphics functions:
draw_rectangle
draws a rectangle, given four
parameters. The first two give the x and y coordinates
of the upper left corner of the rectangle, the third parameter gives the
rectangle’s width, and the fourth parameter gives the rectangle’s
height. So the call draw_rectangle(200, 250, 130, 100)
draws a rectangle with an upper left corner at (200, 250) and a lower
right corner at (330, 350).
draw_triangle
takes six parameters, which it groups
into three consecutive pairs. Each pair gives the coordinates of one
vertex of the triangle. So the call
draw_triangle(200, 250, 330, 250, 265, 200)
draws a
triangle with vertices at (200, 250), (330, 250), and (265,
200).
set_fill_color
says that until told otherwise (by a
subsequent call to set_fill_color
), we are drawing all
filled shapes in the color specified by its three parameters. The
parameters give the fraction of red, green, and blue (in that order)
that, when mixed together, form the color. White would be (1, 1, 1),
black would be (0, 0, 0), pure red would be (1, 0, 0), pure yellow would
be (1, 1, 0) (mixing red and green), and so forth. Play with changing
the parameters to set_fill_color
in the program that draws
the house.
disable_stroke
just says that when we draw
rectangles, circles, and triangles, draw just the inner filled part, not
the outline. See what happens if you comment out the call to
disable_stroke
by putting a #
in front of
it.
Python ignores certain types of whitespace, such as blank lines and spaces after commas. You should use blank lines to group your code into logical segments. A good rule of thumb is that there should be a blank line roughly every 3–10 lines of code. If you have fewer blank lines, look hard to see whether you can break down your code into smaller chunks. You can think of these blank lines as serving the same purpose that new paragraphs do in English writing.
It’s also good style to put a space after every comma, just as you would in written English.
Bear in mind that whitespace at the beginning of a line is very significant. In Python, indentation indicates structure. You’ve already seen how the body of a function is indented by one tab stop. We’ll see plenty of examples of indentation as we go along.