Intro to Computer Science

Unit 1 - Programming Fundamentals: Data Types and Functions

Table of Contents

  1. VS Code and Terminal
  2. Introduction to Python
  3. More Python
  4. Development and Debugging
  5. Programming Basics
  6. Data Types
  7. User Input
  8. Functions, Parameters, and Return Values

1.0. Overview

We're going to look about Computer Science by writing programs using the Python programming language. There are other programming languages, but Python is absolutely the best one for what we're going to be doing.

Let's get started!

1.1. VS Code and Terminal

[NOTE: If you haven't yet installed VS Code, see this video or follow this step-by-step guide.]

Let's set up our work environment by opening a VS Code window on the left side of your screen and a smaller Terminal window on the right side of the screen. This is a classic work environment for writing code.

We'll typically write our programs in VS Code on the left, and then run them using VS Code or the Terminal on the right. Once the program is completed, you'll use the Terminal on the right to upload the program to the server.

(NOTE: VS Code actually has its own built-in Terminal that we'll sometimes use. It's helpful for you to become familiar with using a separate Terminal application as well.)

1.2. Introduction to Python

Let's write our first program, the traditional Hello, World! exercise.

Hello, World! in Python

Do this:

  1. In VS Code, create a new file and save it someplace convenient on your computer as hello_world.py
  2. Enter the following lines of code—a short but complete program—into VS Code.
    def main():
        # This program prints “Hello, world!"
        print("Hello, world!")
    
    if __name__ == "__main__":
        main()
  3. If you've added the Python extension to your VS Code application, the text you write will probably take on different colors due to "syntax highlighting." You should also see a triangle "Play" button on the upper right corner of the VS Code window. Click on this button to run your program.
  4. VS Code should open up its own Terminal pane at the bottom of the screen. It should display a line of text indicating that the program is being run, followed by the output of your program: Hello, world!
  5. If it worked, congratulations! You're a programmer!
  6. If it didn't't work as you expected, or you get a message saying that the program had an error, it's not big deal. Let the debugging begin.
  7. Click back into the program pane above and see if you can figure out what you mistyped. Once you've made your changes, save the program again and try running it again by clicking on the Play triangle.

If your program ran perfectly the first time, congratulations! It doesn't usually happen that way. And if your program didn't work as you expected it would—either because you mistyped something, or because you're still trying to figure out how all of this works, well... welcome to the world of programming. We're going to be writing programs in here, but we're going to spend even more time trying to get the programs to work the way we want them to.

It's like solving a puzzle... and it's a fantastic feeling when you solve the puzzle and get your program to work.

1.3. More Python

We've got a lot more to cover as we learn the Python programming language...

1.3.1. Comments

Real programs have additional components, some of which we're going to introduce right away.

Editing your program

Using your text editor (VSCode), open up and edit your hello_world.py program to include comments: text that is not used by Python, but that is used by programmers to identify and understand the code. Python ignores everything to the right of a #, so we use that to indicate a comment.

#!/usr/bin/env python3
                        
"""
hello_world.py
This is the famous Hello, World! program that one always begins with.
"""

__author__ = "Richard White"
__version__ = "2019-08-19"

def main():
    # This program prints “Hello, world!"
    print(“Hello, world!")

if __name__ == "__main__":
    main()

Save your program and run it again to make sure that it works just as it did before.

You could reasonably wonder why we should include in our program several blank lines and "comments" that don’t make the program run any differently.

Experienced coders already know the answers to these questions. Briefly:

You probably don't want to write a comment for every line of code in a program, although a complex program might actually have more comments than code, to help explain what's happening to others who are trying to understand it.

And as someone who is first learning to write Python code, you will certainly benefit from the comments that will be included in the code presented here. You should do the same for others who will come along and read your code.

1.3.2. Code blocks, or Suites

Programs include logical sections of code blocks, which in Python are called suites.

Suites, or code blocks

A suite in Python is a logical block of code, identified at the beginning by a colon (:), with all lines indented exactly 4 spaces from the previous line.

NOTE: Do not use [tab]s to create your spacing unless you have configured your text editor to replace tabs with spaces. Four spaces may look the same as a [tab], but Python won't be able to run your program correctly. Also, although the "4 spaces" rule is not required by Python—you can actually use any spaced-indent for a suite, as long as the same indent is used consistently throughout the program—in here we'll be using 4-spaces, which is standard Python "best practice."

1.4. Developing and Debugging

Whether you're using Python or some other language, you'll need to know this.

1.4.1. Debugging

You should know right away that programs very rarely work the first time that one writes them. Writing a program has a lot in common with writing an essay or paper:

Writing a paperWriting a program
Planning the essay: outlining, etc.Drawing flowcharts, diagrams of data structures, pseudocoding
Writing the rough draftWriting the program
Editing, revising, polishing up the final draftDebugging the program so that it passes all tests

1.4.2. The Development Process

The Coding Cycle

Whether working from the command line in a Terminal shell or using a sophisticated IDE, the coding process is identical:

  1. Design the program (usually by hand, using pencil and paper)
  2. Write the program (using a text editor or IDE)
  3. Try to compile the program and debug whatever errors there might be
  4. Run a compiled version of the program to confirm that it's working better.
  5. Repeat these steps until you've tested the program sufficiently to have some confidence that it works as it's supposed to.

Compiling and Running your Python program

Writing good software is challenging, but rewarding, and usually even fun.

The process of writing a program involves quite a bit more than simply sitting down at the computer and entering code. A typical problem will require that you:

  1. Analyze the problem
  2. Determine the specifications
  3. Design the program's overall structure
  4. Write the program (lots of testing and debugging here)
  5. Deliver the program
  6. Maintain the program (updating it as required, repairing it as needed)

In this course, you'll often be provided with the first 2 items, and #6 won't typically be something you'll have to worry about.

1.4.3. Types of Errors

There are three specific types of errors that you'll need to keep an eye out for, and fixing errors is what we spend a good amount of time doing.

  1. Syntax errors are caught during compilation of your source code and represent incorrect use of the Python language. Typical syntax errors including

    • misspelling a variable name
    • incorrectly indenting a line
    • incorrect use of parentheses
    • incorrect use of a Python instruction

    The compiler will try to find as many errors as possible at one time, but realize that:

    • an error indicated for one line might have occurred on the previous line, and
    • a whole series of errors may be reported as a result of a single error earlier in the program.
    % python hello_world.py
    File "hello_world.py", line 1
    print("Hello, world!)
                        ^
    SyntaxError: EOL while scanning string literal
    % 
  2. Run-time errors occur while a program is able to run, but doesn't do what it was designed or expected to do. Some examples of run-time errors will cause the program to stop running include:
    • trying to divide by 0
    • the user enters text when a number is expected
    • the user enters a float (decimal point) value when an integer is expected
    % python test.py
    Enter a number: 0
    Traceback (most recent call last):
      File "test.py", line 2, in 
        print (100/val)
    ZeroDivisionError: division by zero
    %
  3. Logic errors are a specific type of error that occurs during runtime. The program will appear to run correctly, but the results produced are incorrect: a program that adds the numbers 1-10 and produces a result of 45 when the correct answer is 55, for example. The only way to catch these types of errors is with testing.
    % python sum1to10
    The sum of the integers 1 to 10 is 45
    Expected result: 55

One thing that helps with avoiding errors is defensive programming: writing well-structured code with comments, and progressively testing the code so that errors in one part don't end up cascading down into other areas of the program.

One three-part "error management" strategy:

  1. learn about common errors and how to avoid them
  2. learn defensive strategies for minimizing likelihood and impact of errors
  3. learn debugging strategies to find and correct errors.

Check - Types of Errors

Identify what type of error—syntax, run-time, or logical—each of the following statements will result in.

Show/hide answers

  • print((10 * 2) / (5 - 2 - 3))
    is a Run-Time error. Dividing by 0 will cause the program to fail when it runs.
  • print("The answer to 2 + 2 is", (2 + 3))
    is a Logical error. The program is producing output, but the output is incorrect.
  • System.out.println("Hello, World!"
    is a Syntax error. There is a missing parenthesis at the end of the string Hello, World!, so this program won't even compile.

1.4.4. Using scp to transfer files

You can use the scp command to transfer files from one computer to another.

The scp command

scp is used to securely copy files from one "source" computer (often your local machine) to another "destination" computer (often the class server) according to the following syntax:

scp <source> <destination>

In order to make this command work, you'll need to provide username and server information as part of the command.

To securely copy a file from the introcs folder located on the Desktop of my laptop computer to my forInstructor directory in my home directory on the server for this course:

% cd ~/Desktop/introcs/
% scp -P 1030 hello_world.py rwhite@crashwhite.polytechnic.org:~/forInstructor/
rwhite@crashwhite.polytechnic.org's password: 
hello_world.py             100%   11KB  11.4KB/s   00:01

You'll see the "100%" confirmation above if the file was successfully able to upload. If you get an error message, it might be that your password was typed incorrectly, or you misspelled the name of the server or your userID, or perhaps you didn't capitalize the -P 1030 . Or maybe you're not in the directory where your program is actually located? Figure it out and try again!

1.5. Programming Basics

1.5.0. Overview

In this session we'll be learning how to assign values to variables, how to perform numeric calculations, how to get input, and how to write a simple program.

1.5.1. Assigning values to variables

The fundamental thing that computers do is calculate the answers to mathematical problems. To do that, we need to be able to store numbers in the computer's memory.

Programmer-assigned value to a variable

To assign a value to a variable in a program:

<variable> = <expression>

Examples:

my_age = 15
height_in_feet = 5.8
height_in_inches = 12 * height_in_feet
my_age = my_age + 1    # I celebrated a birthday!
height_in_inches = height_in_inches + 0.5     # I grew this year!

Let's try writing a program that allows us to convert temperatures from one system to another.

temp_converter.py

The formula for converting from degrees Fahrenheit (U.S. temperature system) to degrees Celsius is

Write a Python program temp_converter.py that takes the temperature in degrees Fahrenheit (say 70°F) and prints out the equivalent temperature in °C.

Show/hide one solution

#!/usr/bin/env python3
"""
temp converter.py
This program converts from degrees F to degrees C
"""

__author__ = "Richard White"
__version__ = "2017-09-08"

def main():
    # The main program will go here
    temp_fahrenheit = 72     
    temp_celsius = (temp_fahrenheit - 32) * 5 / 9
    print(temp_celsius)

if __name__ == "__main__":
    main()

This solution is one way to solve the problem.

1.6. Data Types

In this session we'll be looking at the two different types of numeric data types in Python, seeing how you can import a module to give Python additional capabilities, and looking at local text editor applications.

1.6.0. Overview

Programming languages represent different types of data differently, and it's important for you to be aware of what data type one is working with. Data types in Python include:

To begin, let's look at several of the numeric data types, operations that can be performed on those numbers, and some of the ways we can work with those numbers using functions in the math module.

1.6.1. Integers and Floating Point numbers

Integers

Plain integers are simply that: integers, i.e. numerical values without a decimal point. You can confirm the type of a number by using the type() function in interactive mode:

>>> type(3)
<type 'int'>

Integers in Python3 have unlimited precision: you can perform any calculation you like and Python will be able to handle it without an "overflow" error, which occurs in some languages when a value is too large to be stored in the memory space allocated for it.

Floats

Floats are floating point numbers, i.e. numerical values that do have a decimal point.

>>> type(3.0)
<type 'float'>

Why does a computer need to distinguish between the two? It's all about speed. It's far easier for computers to deal with integers, and therefore far faster for them to perform operations with integers. Differences in speed won't be apparent in most programs that we write, but for any program that performs the same operation thousands, million, or billions of times, working with integers where possible produces a significant increase in speed.

Of course, if you need to work with decimals (floats), then you'll have to use them where appropriate.

In a Terminal, start up an interactive Python interpreter by typing the python and then [Enter]. You'll see three "greater-than" signs as a prompt, which will allow you to try out various Python instructions and expressions. Try out each of the examples here. Can you predict, before you press [Enter], what the output of each will be?

>>> 5 + 2
>>> 5.0 + 2
>>> 5.0 / 2
>>> 5 / 2
>>> 5 // 2  # how is this different?
>>> 5 % 2  # this is related to the last one
>>> 5 * 2
>>> 5 * 2.0
>>> 5 ** 2
>>> 2. ** 0.5

Note that the // operator allows for "whole number" division—it returns the integer result of the division without a decimal and without any remainder.

The modulo operator % gives you that remainder.

These two division strategies will be useful to us later on.

You can use Python's built-in functions to convert from one data type to another:

>>> float(3)
3.0
>>> int(3.7)
3
>>> round(3.7)
4

1.7. User Input

It's important for us to be able to store data—numbers like 2.7 and strings like "Lola"—in the computer's memory. We also want to have the person running the program—the "user"&mdashp;to be able to enter data for use in a program as well.

Let's see how to do that.

1.7.1. Entering strings

Let's take our original hello_world.py program and personalize it so that it prints out a greeting with my name in it.

def main():
    name = "Richard"
    print("Hello", name)
    
if __name__ == "__main__":
    main()

Notice that we're using the print() function to print out two things: the string "Hello" and whatever is stored in name, which is another string. The comma separates those two items in the print statement but isn't printed out itself.

This program works as you'd probably expect.

Hello Richard

Ideally, however, we want the program to print "Hello" to anybody who's running it, without the programmer having to rewrite the program.

The input() function: User-assigned string value to a variable

To allow a user to enter a string value while the program is running:

<variable> = input()  # for entering strings

The input() function takes whatever is entered as a string, a series of characters.

It is also possible to include a simple prompt as part of the function. If we want to have the user enter their name and age, we could do it this way:

print("Enter your name: ")
name = input()

Or we can include the prompt as part of the input statement like this:

name = input("Enter your name"))

With this in mind, we could rewrite our personalized hello_world_personal.py to look like this:

def main():
    name = input("Enter your name, please: ")
    print("Hello", name)

Much nicer!

1.7.2. Entering numbers

Note that the input() function only gives us a string of characters. If the string 37 or 6.5 is entered, how can we convert those characters to numeric values?

The input() function: User-assigned numeric value to a variable

If you want an input string to be evaluated as a number, convert the input using the int() or float() function.

<variable> = float(input()) # to take a string entered and
                            # evaluate it as a number with a decimal point
                            # (a "floating-point" number).

or

<variable> = int(input()) # to take a string entered and
                          # evaluate it as an integer

temp_converter_input.py

Make a new version of the previous program temp_converter.py that it asks the user for a name and a temperature, and then prints out a custom message of the temperature in degrees C using their name.

Note: You can print multiple items with a single print statement by separating each item from the others with a comma (,).

Show/hide one solution

#!/usr/bin/env python3
"""
temp_converter_input.py
This program converts from degrees F to degrees C
"""

__author__ = "Richard White"
__version__ = "2017-09-08"

def main():
    name = input("Enter your name: ")
    temp_fahrenheit = float(input("Enter the temperature in degrees F: "))
    temp_celsius = (temp_fahrenheit - 32) * 5 / 9
    print(name, "the equivalent temperature in Celsius is", temp_celsius)

if __name__ == "__main__":
    main()

1.8. Functions, Parameters, and Return Values

1.8.0. Overview

In this session we'll be taking our first steps toward writing larger, more complex programs. We'll look at how writing procedural functions can help us better organize our code and make it less redundant, and how to write functions that uses parameters and return values to communicate with the programs that call them.

1.8.1. Functions and Parameters

1.8.1.0. Definition and Uses of Functions

Functions

A function is simply a small program inside a larger one, whose purpose is to:

Generally speaking, you should include functions in your program if:

In fact, a popular acronym among software engineers is DRY: Don't Repeat Yourself. If you do find yourself rewriting lots of segments of code, you should probably try to find a way to write the code more efficiently.

One way of reducing the amount of repeated code that we have to write is by using loops, which we'll learn about soon. Another very important strategy is to organize code into functions.

Defining a Function

Just as we've used def main(): to define a main block of code that runs, we can define other functions with blocks of code that will execute when we "call" the function. As an example, here's a short (and not very useful) function to say "Hello" to somebody:

"""
Demonstrating a function
"""

def say_hello():
    print("Hello!")

def main():
    print("Check out this function!")
    say_hello()

if __name__ == "__main__":
    main()

These lines for the function just define the function, but the code doesn't actually execute until we call it:

say_hello()

At this point, the "Hello!" message is displayed.

1.8.1.1. Standalone functions

I'm welcoming guests to my party and I find myself saying the same thing over and over again as each guest shows up at the door. I've written a program to print what I'm saying:

"""
party.py
Welcomes guests to my party
"""

def main():
    guest = "Devi"
    print("Welcome,",guest)
    print("Food is over there,")
    print("drinks are over here,")
    print("I hope you have a great time!")
    
    guest = "Emilio"
    print("Welcome,",guest)
    print("Food is over there,")
    print("drinks are over here,")
    print("I hope you have a great time!")
    
    guest = "Apollo"
    print("Welcome,",guest)
    print("Food is over there,")
    print("drinks are over here,")
    print("I hope you have a great time!")
    
if __name__ == "__main__":
    main()

This program works just great, but you can see that I've had to repeat my little speech quite a few times. We can make the program a little more efficient by writing a function to print out the parts that are repeated.

This program produces exactly the same output:

"""
party.py
Welcomes guests to my party
"""

def welcome():
    """Prints out a welcome to party guests.
    """
    print("Food is over there,")
    print("drinks are over here,")
    print("I hope you have a great time!")
    
def main():
    guest = "Devi"
    print("Welcome,",guest)
    welcome()                   # calls the function
    
    guest = "Emilio"
    print("Welcome,",guest)
    welcome()                   # calls the function
    				
    guest = "Apollo"
    print("Welcome,",guest)
    welcome()                   # calls the function
    
if __name__ == "__main__":
    main()

This is quite a bit more efficient than what I did before. Each time I "call" the welcome() function in the main, the instructions in that welcome() function are performed.

1.8.1.2. Functions with parameters

We can make our function even more efficient by moving that print("Welcome,",name) instruction side the function, but when we first do that, we run into a problem:

def welcome():
    """Prints out a welcome to party guests.
    """
    print("Welcome,",guest)
    print("Food is over there,")
    print("drinks are over here,")
    print("I hope you have a great time!")
    
    Traceback (most recent call last):
  File "party.py", line 27, in 
    main()
  File "party.py", line 16, in main
    welcome()
  File "party.py", line 8, in welcome
    print("Welcome,",name)
NameError: global name 'guest' is not defined

The issue here is that although the main() program knows who the guest is, the function doesn't. We need to send that bit of information in via a parameter.

Parameters

A parameter is information that is passed into a function.

A formal parameter is included in parentheses as part of the function definition. The argument—either a variable or a value—is given in parentheses when the function is called.

The working version of the program looks like this:

"""
party.py
Welcomes guests to my party
"""

def welcome(guest):
    """Prints out a welcome to a party guest.
    """
    print("Welcome,",guest)
    print("Food is over there,")
    print("drinks are over here,")
    print("I hope you have a great time!")
    
def main():
    guest = "Devi"
    welcome(guest)                   # calls the function
    
    guest = "Emilio"
    welcome(guest)                   # calls the function
    
    guest = "Apollo"
    welcome(guest)                   # calls the function
    
if __name__ == "__main__":
    main()

This works just as it should!

1.8.1.3. Scope

Scope

Scope refers to the area in a program where a particular variable may be used.

Local scope variables may be used "locally" (in the current function), but don't have any value outside the function.

Global scope variables have value outside a given function, and may be referred to inside a function, but they typically can't be changed by that function.

Take a look at this Calculator program.

"""Calculator Program
This program takes two numbers entered by the user and performs a mathematical operation on them.
"""

def add_them(number1, number2):
    total = number1 + number2
    print("The sum of", number1, "and", number2)
    print("is", total)

def main():
    n1 = float(input("Enter a number: "))
    n2 = float(input("Enter a second number: "))
    add_them(n1, n2)

if __name__ == "__main__":
    main()

In our Calculator Program, n1 and n2 are local to main(), and global to add_them. number1 and number2 are local to add_them, and undefined outside of that function.

This program works fine. When the main program calls add_them, the values for n1 and n2 are "sent" into the add_them function via the parameters number1 and number2. The function is able to use those variable, which have local scope in the function.

Exercise: Scope

Examine the following function, and predict why this program won't work.

def add_them(number1, number2):
    answer = number1 + number2

def main():
    n1 = float(input("Enter a number: "))
    n2 = float(input("Enter a second number: "))
    add_them(n1, n2)
    print(answer)

if __name__ == "__main__":
main()

Here, this program won't run. The variable answer in the main method hasn't been defined there. It's true that answer has been defined in the add_them function where it has local scope, but that variable is undefined outside of the function.

Why is Python so concerned about scope? Wouldn't it be easier if the programs could just access all of the variables from anywhere they are in the program?

1.8.1.4. Getting information back out of a function

We've learned that you can pass information into a function using parameters. But how do you get information back out?

Our programming solution is to return a value.

return statements

A return statement in a function that returns operation of a program back to the point where the function was called. Any variables included as part of the return statement are sent back to the function call as a result.

def add_them(a,b):
    return a + b    # Calculate a + b
                    # and send result back
                    # to function call

Here's a version of our program, then, that does work:

"""Calculator Program that works!
"""

def add_them(number1, number2):
    total = number1 + number2
    return total

def main():
    n1 = float(input("Enter a number: "))
    n2 = float(input("Enter a second number: "))
    answer = add_them(n1, n2)               # take the result returned from the function
                                            # and store it in a variable so we can use it
    print(answer)

if __name__ == "__main__":
    main()

One common use for functions is to gather user input. Writing separate functions for "initializing" a program (setting initial values for data) and actually processing that data is very common.

Functions for input

Write a small program that includes a function get_input to get the user's name and age. The function should pass this information back to the main program.

Show/hide solution

def get_input():
        name = input("Enter your name: ")
        age = float(input("Enter your age: "))
        return name, age            # You can return two answers, separated by commas!
    
    def main():
        user, age = get_input()   # Call the function and store the answer in two variables
        print(user, ", you are", age, "years old.")

Now try this one:

Functions for input and calculation

Write a small program called quadrilateral.py that includes two functions: one to get the dimensions of a quadrilateral (and return those dimensions to the main()), and one that uses the information from the first function to calculate the area and perimeter of that quadrilateral and return those to the main(). The main program should then print out the results of the analysis.

Show/hide solution

#!/usr/bin/env python3
"""
quadrilateral.py
This program identifies the area and perimeter for a quadrilateral 
of dimensions provided by the user. It also uses functions!
@author Richard White
@version 2017-09-27
"""

def get_dimensions():
    length = float(input("Enter length of quadrilateral: "))
    width = float(input("Now enter width:"))
    return length, width

def calc_area_perimeter(length, width):
    area = length * width
    perimeter = 2 * length + 2 * width
    return area, perimeter

def main():
    l, w = get_dimensions()
    a, p = calc_area_perimeter(l, w)
    print("The area and perimeter of your")
    print("quadrilateral are", a, "and", p)

if __name__ == "__main__":
    main()

As you're writing this program, you want to be able to trace exactly what values each variable has as the information is passed to and from the functions.

1.8.2. The random Module

We've already discussed the math module, and how you can import that module to use various methods that will allow your Python program to perform mathematical calculations.

Now let's look at another useful module, and learn how to get help using that module.

The random Module

The random module in Python provides various random generators that can be used to produce random values or random select items from a list.

Common methods used in the random module include:

Here's an example of how you can use that module to generate a random roll of a six-sided die:

#!/usr/bin/env python3
"""
Using the random module to simulate rolling a die.
"""

import random

def main():
    roll = random.randrange(6) + 1      
    # randrange randomly gets an integer from 0-5 inclusive.
    # Adding one gives us a value from 1-6, inclusive.
    print(roll)

if __name__ == "__main__":
    main()

There are other methods that can be used in the random module. You can find them by using Python's help function in interactive mode.