Python Programming: An Introduction to Computer Science Chapter 1 Computers and Programs Python Programming, 2/e Python Programming, 2/e
Objectives To understand the respective roles of hardware and software in a computing system. To learn what computer scientists study and the techniques that they use. To understand the basic design of a modern computer. Python Programming, 2/e
Objectives (cont.) To understand the form and function of computer programming languages. To begin using the Python programming language. To learn about chaotic models and their implications for computing. Python Programming, 2/e
The Universal Machine A modern computer can be defined as “a machine that stores and manipulates information under the control of a changeable program.” Two key elements: Computers are devices for manipulating information. Computers operate under the control of a changeable program. Python Programming, 2/e
The Universal Machine What is a computer program? A detailed, step-by-step set of instructions telling a computer what to do. If we change the program, the computer performs a different set of actions or a different task. The machine stays the same, but the program changes! Python Programming, 2/e
The Universal Machine Programs are executed, or carried out. All computers have the same power, with suitable programming, i.e. each computer can do the things any other computer can do. Python Programming, 2/e
Program Power Software (programs) rule the hardware (the physical machine). The process of creating this software is called programming. Why learn to program? Fundamental part of computer science Having an understanding of programming helps you have an understanding of the strengths and limitations of computers. Python Programming, 2/e
Program Power Helps you become a more intelligent user of computers It can be fun! Form of expression Helps the development of problem solving skills, especially in analyzing complex systems by reducing them to interactions between simpler systems. Programmers are in great demand! Python Programming, 2/e
What is Computer Science? It is not the study of computers! “Computers are to computer science what telescopes are to astronomy.” – E. Dijkstra The question becomes, “What processes can be described?” This question is really, “What can be computed?” Python Programming, 2/e
What is Computer Science? Design One way to show a particular problem can be solved is to actually design a solution. This is done by developing an algorithm, a step-by-step process for achieving the desired result. One problem – it can only answer in the positive. You can’t prove a negative! Python Programming, 2/e
What is Computer Science? Analysis Analysis is the process of examining algorithms and problems mathematically. Some seemingly simple problems are not solvable by any algorithm. These problems are said to be unsolvable. Problems can be intractable if they would take too long or take too much memory to be of practical value. Python Programming, 2/e
What is Computer Science? Experimentation Some problems are too complex for analysis. Implement a system and then study its behavior. Python Programming, 2/e
Hardware Basics The central processing unit (CPU) is the “brain” of a computer. The CPU carries out all the basic operations on the data. Examples: simple arithmetic operations, testing to see if two numbers are equal. Python Programming, 2/e
Hardware Basics Memory stores programs and data. CPU can only directly access information stored in main memory (RAM or Random Access Memory). Main memory is fast, but volatile, i.e. when the power is interrupted, the contents of memory are lost. Secondary memory provides more permanent storage: magnetic (hard drive, floppy), optical (CD, DVD) Python Programming, 2/e
Hardware Basics Input devices Output devices Information is passed to the computer through keyboards, mice, etc. Output devices Processed information is presented to the user through the monitor, printer, etc. Python Programming, 2/e
Hardware Basics Fetch-Execute Cycle First instruction retrieved from memory Decode the instruction to see what it represents Appropriate action carried out. Next instruction fetched, decoded, and executed. Lather, rinse, repeat! Python Programming, 2/e
Programming Languages Natural language has ambiguity and imprecision problems when used to describe complex algorithms. Programs expressed in an unambiguous , precise way using programming languages. Every structure in programming language has a precise form, called its syntax Every structure in programming language has a precise meaning, called its semantics. Python Programming, 2/e
Programming Languages Programming language like a code for writing the instructions the computer will follow. Programmers will often refer to their program as computer code. Process of writing an algorithm in a programming language often called coding. Python Programming, 2/e
Programming Languages High-level computer languages Designed to be used and understood by humans Low-level language Computer hardware can only understand a very low level language known as machine language Python Programming, 2/e
Programming Languages Add two numbers: Load the number from memory location 2001 into the CPU Load the number from memory location 2002 into the CPU Add the two numbers in the CPU Store the result into location 2003 In reality, these low-level instructions are represented in binary (1’s and 0’s) Python Programming, 2/e
Programming Languages High-level language c = a + b This needs to be translated into machine language that the computer can execute. Compilers convert programs written in a high-level language into the machine language of some computer. Python Programming, 2/e
Programming Languages Interpreters simulate a computer that understands a high-level language. The source program is not translated into machine language all at once. An interpreter analyzes and executes the source code instruction by instruction. Python Programming, 2/e
Programming Languages Compiling vs. Interpreting Once program is compiled, it can be executed over and over without the source code or compiler. If it is interpreted, the source code and interpreter are needed each time the program runs Compiled programs generally run faster since the translation of the source code happens only once. Python Programming, 2/e
Programming Languages Interpreted languages are part of a more flexible programming environment since they can be developed and run interactively Interpreted programs are more portable, meaning the executable code produced from a compiler for a Pentium won’t run on a Mac, without recompiling. If a suitable interpreter already exists, the interpreted code can be run with no modifications. Python Programming, 2/e
The Magic of Python When you start Python, you will see something like: Python 3.1.2 (r312:79149, Mar 21 2010, 00:41:52) [MSC v.1500 32 bit (Intel)] on win32 Type "copyright", "credits" or "license()" for more information. >>> Python Programming, 2/e
The Magic of Python The “>>>” is a Python prompt indicating that Python is ready for us to give it a command. These commands are called statements. >>> print("Hello, world“) Hello, world >>> print(2+3) 5 >>> print("2+3=", 2+3) 2+3= 5 >>> Python Programming, 2/e
The Magic of Python Usually we want to execute several statements together that solve a common problem. One way to do this is to use a function. >>> def hello(): print("Hello") print("Computers are Fun") >>> Python Programming, 2/e
The Magic of Python >>> def hello(): print("Hello") print("Computers are Fun") >>> The first line tells Python we are defining a new function called hello. The following lines are indented to show that they are part of the hello function. The blank line (hit enter twice) lets Python know the definition is finished. Python Programming, 2/e
The Magic of Python >>> def hello(): print("Hello") print("Computers are Fun") >>> Notice that nothing has happened yet! We’ve defined the function, but we haven’t told Python to perform the function! A function is invoked by typing its name. >>> hello() Hello Computers are Fun >>> Python Programming, 2/e
The Magic of Python What’s the deal with the ()’s? Commands can have changeable parts called parameters that are placed between the ()’s. >>> def greet(person): print("Hello",person) print ("How are you?") >>> Python Programming, 2/e
The Magic of Python >>> greet("Terry") Hello Terry How are you? >>> greet("Paula") Hello Paula How are you? >>> When we use parameters, we can customize the output of our function. Python Programming, 2/e
The Magic of Python When we exit the Python prompt, the functions we’ve defined cease to exist! Programs are usually composed of functions, modules, or scripts that are saved on disk so that they can be used again and again. A module file is a text file created in text editing software (saved as “plain text”) that contains function definitions. A programming environment is designed to help programmers write programs and usually includes automatic indenting, highlighting, etc. Python Programming, 2/e
The Magic of Python # File: chaos.py # A simple program illustrating chaotic behavior def main(): print("This program illustrates a chaotic function") x = eval(input("Enter a number between 0 and 1: ")) for i in range(10): x = 3.9 * x * (1 - x) print(x) main() We’ll use filename.py when we save our work to indicate it’s a Python program. In this code we’re defining a new function called main. The main() at the end tells Python to run the code. Python Programming, 2/e
The Magic of Python >>> This program illustrates a chaotic function Enter a number between 0 and 1: .5 0.975 0.0950625 0.335499922266 0.869464925259 0.442633109113 0.962165255337 0.141972779362 0.4750843862 0.972578927537 0.104009713267 Python Programming, 2/e
Inside a Python Program # File: chaos.py # A simple program illustrating chaotic behavior Lines that start with # are called comments Intended for human readers and ignored by Python Python skips text from # to end of line Python Programming, 2/e
Inside a Python Program def main(): Beginning of the definition of a function called main Since our program has only this one module, it could have been written without the main function. The use of main is customary, however. Python Programming, 2/e
Inside a Python Program print("This program illustrates a chaotic function") This line causes Python to print a message introducing the program. Python Programming, 2/e
Inside a Python Program x = eval(input("Enter a number between 0 and 1: ")) x is an example of a variable A variable is used to assign a name to a value so that we can refer to it later. The quoted information is displayed, and the number typed in response is stored in x. Python Programming, 2/e
Inside a Python Program for i in range(10): For is a loop construct A loop tells Python to repeat the same thing over and over. In this example, the following code will be repeated 10 times. Python Programming, 2/e
Inside a Python Program x = 3.9 * x * (1 - x) print(x) These lines are the body of the loop. The body of the loop is what gets repeated each time through the loop. The body of the loop is identified through indentation. The effect of the loop is the same as repeating this two lines 10 times! Python Programming, 2/e
Inside a Python Program for i in range(10): x = 3.9 * x * (1 - x) print(x) These are equivalent! x = 3.9 * x * (1 - x) print(x) Python Programming, 2/e
Inside a Python Program x = 3.9 * x * (1 - x) This is called an assignment statement The part on the right-hand side (RHS) of the “=“ is a mathematical expression. * is used to indicate multiplication Once the value on the RHS is computed, it is stored back into (assigned) into x Python Programming, 2/e
Inside a Python Program main() This last line tells Python to execute the code in the function main Python Programming, 2/e
Chaos and Computers The chaos.py program: def main(): print("This program illustrates a chaotic function") x = eval(input("Enter a number between 0 and 1: ")) for i in range(10): x = 3.9 * x * (1 - x) print(x) main() For any given input, returns 10 seemingly random numbers between 0 and 1 It appears that the value of x is chaotic Python Programming, 2/e
Chaos and Computers The function computed by program has the general form where k is 3.9 This type of function is known as a logistic function. Models certain kinds of unstable electronic circuits. Very small differences in initial value can have large differences in the output. Python Programming, 2/e
Chaos and Computers Input: 0.25 0.73125 0.76644140625 0.698135010439 0.82189581879 0.570894019197 0.955398748364 0.166186721954 0.540417912062 0.9686289303 0.118509010176 Input: 0.26 0.75036 0.73054749456 0.767706625733 0.6954993339 0.825942040734 0.560670965721 0.960644232282 0.147446875935 0.490254549376 0.974629602149 Python Programming, 2/e
Python Programming: An Introduction to Computer Science Chapter 2 Python Programming, 2/e
Objectives To be able to understand and write Python statements to output information to the screen, assign values to variables, get numeric information entered from the keyboard, and perform a counted loop Python Programming, 2/e
The Software Development Process The process of creating a program is often broken down into stages according to the information that is produced in each phase. Python Programming, 2/e
The Software Development Process Analyze the Problem Figure out exactly the problem to be solved. Try to understand it as much as possible. Python Programming, 2/e
The Software Development Process Determine Specifications Describe exactly what your program will do. Don’t worry about how the program will work, but what it will do. Includes describing the inputs, outputs, and how they relate to one another. Python Programming, 2/e
The Software Development Process Create a Design Formulate the overall structure of the program. This is where the how of the program gets worked out. You choose or develop your own algorithm that meets the specifications. Python Programming, 2/e
The Software Development Process Implement the Design Translate the design into a computer language. In this course we will use Python. Python Programming, 2/e
The Software Development Process Test/Debug the Program Try out your program to see if it worked. If there are any errors (bugs), they need to be located and fixed. This process is called debugging. Your goal is to find errors, so try everything that might “break” your program! Python Programming, 2/e
The Software Development Process Maintain the Program Continue developing the program in response to the needs of your users. In the real world, most programs are never completely finished – they evolve over time. Python Programming, 2/e
Example Program: Temperature Converter Analysis – the temperature is given in Celsius, user wants it expressed in degrees Fahrenheit. Specification Input – temperature in Celsius Output – temperature in Fahrenheit Output = 9/5(input) + 32 Python Programming, 2/e
Example Program: Temperature Converter Design Input, Process, Output (IPO) Prompt the user for input (Celsius temperature) Process it to convert it to Fahrenheit using F = 9/5(C) + 32 Output the result by displaying it on the screen Python Programming, 2/e
Example Program: Temperature Converter Before we start coding, let’s write a rough draft of the program in pseudocode Pseudocode is precise English that describes what a program does, step by step. Using pseudocode, we can concentrate on the algorithm rather than the programming language. Python Programming, 2/e
Example Program: Temperature Converter Pseudocode: Input the temperature in degrees Celsius (call it celsius) Calculate fahrenheit as (9/5)*celsius+32 Output fahrenheit Now we need to convert this to Python! Python Programming, 2/e
Example Program: Temperature Converter #convert.py # A program to convert Celsius temps to Fahrenheit # by: Susan Computewell def main(): celsius = eval(input("What is the Celsius temperature? ")) fahrenheit = (9/5) * celsius + 32 print("The temperature is ",fahrenheit," degrees Fahrenheit.") main() Python Programming, 2/e Python Programming, 1/e
Example Program: Temperature Converter Once we write a program, we should test it! >>> What is the Celsius temperature? 0 The temperature is 32.0 degrees Fahrenheit. >>> main() What is the Celsius temperature? 100 The temperature is 212.0 degrees Fahrenheit. What is the Celsius temperature? -40 The temperature is -40.0 degrees Fahrenheit. Python Programming, 2/e
Elements of Programs Names Names are given to variables (celsius, fahrenheit), modules (main, convert), etc. These names are called identifiers Every identifier must begin with a letter or underscore (“_”), followed by any sequence of letters, digits, or underscores. Identifiers are case sensitive. Python Programming, 2/e
Elements of Programs These are all different, valid names X Celsius Spam spam spAm Spam_and_Eggs Spam_And_Eggs Python Programming, 2/e
Elements of Programs Some identifiers are part of Python itself. These identifiers are known as reserved words. This means they are not available for you to use as a name for a variable, etc. in your program. and, del, for, is, raise, assert, elif, in, print, etc. For a complete list, see table 2.1 Python Programming, 2/e
Elements of Programs Expressions The fragments of code that produce or calculate new data values are called expressions. Literals are used to represent a specific value, e.g. 3.9, 1, 1.0 Simple identifiers can also be expressions. Python Programming, 2/e
Elements of Programs >>> x = 5 >>> x 5 >>> print(x) >>> print(spam) Traceback (most recent call last): File "<pyshell#15>", line 1, in -toplevel- print spam NameError: name 'spam' is not defined >>> NameError is the error when you try to use a variable without a value assigned to it. Python Programming, 2/e
Elements of Programs Simpler expressions can be combined using operators. +, -, *, /, ** Spaces are irrelevant within an expression. The normal mathematical precedence applies. ((x1 – x2) / 2*n) + (spam / k**3) Python Programming, 2/e
Elements of Programs Output Statements A print statement can print any number of expressions. Successive print statements will display on separate lines. A bare print will print a blank line. Python Programming, 2/e
Elements of Programs print(3+4) print(3, 4, 3+4) print() print(3, 4, end=" "), print(3 + 4) print("The answer is", 3+4) 7 3 4 7 The answer is 7 Python Programming, 2/e
Assignment Statements Simple Assignment <variable> = <expr> variable is an identifier, expr is an expression The expression on the RHS is evaluated to produce a value which is then associated with the variable named on the LHS. Python Programming, 2/e
Assignment Statements x = 3.9 * x * (1-x) fahrenheit = 9/5 * celsius + 32 x = 5 Python Programming, 2/e
Assignment Statements Variables can be reassigned as many times as you want! >>> myVar = 0 >>> myVar >>> myVar = 7 7 >>> myVar = myVar + 1 8 >>> Python Programming, 2/e
Assignment Statements Variables are like a box we can put values in. When a variable changes, the old value is erased and a new one is written in. Python Programming, 2/e
Assignment Statements Technically, this model of assignment is simplistic for Python. Python doesn't overwrite these memory locations (boxes). Assigning a variable is more like putting a “sticky note” on a value and saying, “this is x”. Python Programming, 2/e
Assigning Input The purpose of an input statement is to get input from the user and store it into a variable. <variable> = eval(input(<prompt>)) Python Programming, 2/e
Assigning Input First the prompt is printed The input part waits for the user to enter a value and press <enter> The expression that was entered is evaluated to turn it from a string of characters into a Python value (a number). The value is assigned to the variable. Python Programming, 2/e
Simultaneous Assignment Several values can be calculated at the same time <var>, <var>, … = <expr>, <expr>, … Evaluate the expressions in the RHS and assign them to the variables on the LHS Python Programming, 2/e
Simultaneous Assignment sum, diff = x+y, x-y How could you use this to swap the values for x and y? Why doesn’t this work? x = y y = x We could use a temporary variable… Python Programming, 2/e
Simultaneous Assignment We can swap the values of two variables quite easily in Python! x, y = y, x >>> x = 3 >>> y = 4 >>> print x, y 3 4 >>> x, y = y, x 4 3 Python Programming, 2/e
Simultaneous Assignment We can use this same idea to input multiple variables from a single input statement! Use commas to separate the inputs def spamneggs(): spam, eggs = eval(input("Enter # of slices of spam followed by # of eggs: ")) print ("You ordered", eggs, "eggs and", spam, "slices of spam. Yum!“) >>> spamneggs() Enter the number of slices of spam followed by the number of eggs: 3, 2 You ordered 2 eggs and 3 slices of spam. Yum! >>> Python Programming, 2/e
Definite Loops A definite loop executes a definite number of times, i.e., at the time Python starts the loop it knows exactly how many iterations to do. for <var> in <sequence>: <body> The beginning and end of the body are indicated by indentation. Python Programming, 2/e
Definite Loops for <var> in <sequence>: <body> The variable after the for is called the loop index. It takes on each successive value in sequence. Python Programming, 2/e
Definite Loops >>> for i in [0,1,2,3]: print (i) 1 2 3 1 2 3 >>> for odd in [1, 3, 5, 7]: print(odd*odd) 9 25 49 >>> Python Programming, 2/e
Definite Loops In chaos.py, what did range(10) do? >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] range is a built-in Python function that generates a sequence of numbers, starting with 0. list is a built-in Python function that turns the sequence into an explicit list The body of the loop executes 10 times. Python Programming, 2/e
Definite Loops for loops alter the flow of program execution, so they are referred to as control structures. Python Programming, 2/e
Example Program: Future Value Analysis Money deposited in a bank account earns interest. How much will the account be worth 10 years from now? Inputs: principal, interest rate Output: value of the investment in 10 years Python Programming, 2/e
Example Program: Future Value Specification User enters the initial amount to invest, the principal User enters an annual percentage rate, the interest The specifications can be represented like this … Python Programming, 2/e
Example Program: Future Value Inputs principal The amount of money being invested, in dollars apr The annual percentage rate expressed as a decimal number. Output The value of the investment 10 years in the future Relatonship Value after one year is given by principal * (1 + apr). This needs to be done 10 times. Python Programming, 2/e
Example Program: Future Value Design Print an introduction Input the amount of the principal (principal) Input the annual percentage rate (apr) Repeat 10 times: principal = principal * (1 + apr) Output the value of principal Python Programming, 2/e
Example Program: Future Value Implementation Each line translates to one line of Python (in this case) Print an introduction print ("This program calculates the future") print ("value of a 10-year investment.") Input the amount of the principal principal = eval(input("Enter the initial principal: ")) Python Programming, 2/e
Example Program: Future Value Input the annual percentage rate apr = eval(input("Enter the annual interest rate: ")) Repeat 10 times: for i in range(10): Calculate principal = principal * (1 + apr) principal = principal * (1 + apr) Output the value of the principal at the end of 10 years print ("The value in 10 years is:", principal) Python Programming, 2/e
Example Program: Future Value # futval.py # A program to compute the value of an investment # carried 10 years into the future def main(): print("This program calculates the future value of a 10-year investment.") principal = eval(input("Enter the initial principal: ")) apr = eval(input("Enter the annual interest rate: ")) for i in range(10): principal = principal * (1 + apr) print ("The value in 10 years is:", principal) main() Python Programming, 2/e
Example Program: Future Value >>> main() This program calculates the future value of a 10-year investment. Enter the initial principal: 100 Enter the annual interest rate: .03 The value in 10 years is: 134.391637934 Enter the annual interest rate: .10 The value in 10 years is: 259.37424601 Python Programming, 2/e
Python Programming: An Introduction to Computer Science Chapter 3 Computing with Numbers Python Programming, 2/e
Objectives To understand the concept of data types. To be familiar with the basic numeric data types in Python. To understand the fundamental principles of how numbers are represented on a computer. Python Programming, 2/e
Objectives (cont.) To be able to use the Python math library. To understand the accumulator program pattern. To be able to read and write programs that process numerical data. Python Programming, 2/e
Numeric Data Types The information that is stored and manipulated bu computers programs is referred to as data. There are two different kinds of numbers! (5, 4, 3, 6) are whole numbers – they don’t have a fractional part (.25, .10, .05, .01) are decimal fractions Python Programming, 2/e
Numeric Data Types Inside the computer, whole numbers and decimal fractions are represented quite differently! We say that decimal fractions and whole numbers are two different data types. The data type of an object determines what values it can have and what operations can be performed on it. Python Programming, 2/e
Numeric Data Types Whole numbers are represented using the integer (int for short) data type. These values can be positive or negative whole numbers. Python Programming, 2/e
Numeric Data Types Numbers that can have fractional parts are represented as floating point (or float) values. How can we tell which is which? A numeric literal without a decimal point produces an int value A literal that has a decimal point is represented by a float (even if the fractional part is 0) Python Programming, 2/e
Numeric Data Types Python has a special function to tell us the data type of any value. >>> type(3) <class 'int'> >>> type(3.1) <class 'float'> >>> type(3.0) >>> myInt = 32 >>> type(myInt) >>> Python Programming, 2/e
Numeric Data Types Why do we need two number types? Values that represent counts can’t be fractional (you can’t have 3 ½ quarters) Most mathematical algorithms are very efficient with integers The float type stores only an approximation to the real number being represented! Since floats aren’t exact, use an int whenever possible! Python Programming, 2/e
Numeric Data Types Operations on ints produce ints, operations on floats produce floats (except for /). >>> 3.0+4.0 7.0 >>> 3+4 7 >>> 3.0*4.0 12.0 >>> 3*4 12 >>> 10.0/3.0 3.3333333333333335 >>> 10/3 >>> 10 // 3 3 >>> 10.0 // 3.0 3.0 Python Programming, 2/e
Numeric Data Types Integer division produces a whole number. That’s why 10//3 = 3! Think of it as ‘gozinta’, where 10//3 = 3 since 3 gozinta (goes into) 10 3 times (with a remainder of 1) 10%3 = 1 is the remainder of the integer division of 10 by 3. a = (a/b)(b) + (a%b) Python Programming, 2/e
Using the Math Library Besides (+, -, *, /, //, **, %, abs), we have lots of other math functions available in a math library. A library is a module with some useful definitions/functions. Python Programming, 2/e
Using the Math Library Let’s write a program to compute the roots of a quadratic equation! The only part of this we don’t know how to do is find a square root… but it’s in the math library! Python Programming, 2/e
Using the Math Library To use a library, we need to make sure this line is in our program: import math Importing a library makes whatever functions are defined within it available to the program. Python Programming, 2/e
Using the Math Library To access the sqrt library routine, we need to access it as math.sqrt(x). Using this dot notation tells Python to use the sqrt function found in the math library module. To calculate the root, you can do discRoot = math.sqrt(b*b – 4*a*c) Python Programming, 2/e
Using the Math Library Python Programming, 2/e # quadratic.py # A program that computes the real roots of a quadratic equation. # Illustrates use of the math library. # Note: This program crashes if the equation has no real roots. import math # Makes the math library available. def main(): print("This program finds the real solutions to a quadratic") print() a, b, c = eval(input("Please enter the coefficients (a, b, c): ")) discRoot = math.sqrt(b * b - 4 * a * c) root1 = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a) print("The solutions are:", root1, root2 ) main() Python Programming, 2/e
Using the Math Library What do you suppose this means? This program finds the real solutions to a quadratic Please enter the coefficients (a, b, c): 3, 4, -1 The solutions are: 0.215250437022 -1.54858377035 What do you suppose this means? Please enter the coefficients (a, b, c): 1, 2, 3 Traceback (most recent call last): File "<pyshell#26>", line 1, in -toplevel- main() File "C:\Documents and Settings\Terry\My Documents\Teaching\W04\CS 120\Textbook\code\chapter3\quadratic.py", line 14, in main discRoot = math.sqrt(b * b - 4 * a * c) ValueError: math domain error >>> Python Programming, 2/e
Math Library If a = 1, b = 2, c = 3, then we are trying to take the square root of a negative number! Using the sqrt function is more efficient than using **. How could you use ** to calculate a square root? Python Programming, 2/e
Accumulating Results: Factorial Say you are waiting in a line with five other people. How many ways are there to arrange the six people? 720 -- 720 is the factorial of 6 (abbreviated 6!) Factorial is defined as: n! = n(n-1)(n-2)…(1) So, 6! = 6*5*4*3*2*1 = 720 Python Programming, 2/e
Accumulating Results: Factorial How we could we write a program to do this? Input number to take factorial of, n Compute factorial of n, fact Output fact Python Programming, 2/e
Accumulating Results: Factorial How did we calculate 6!? 6*5 = 30 Take that 30, and 30 * 4 = 120 Take that 120, and 120 * 3 = 360 Take that 360, and 360 * 2 = 720 Take that 720, and 720 * 1 = 720 Python Programming, 2/e
Accumulating Results: Factorial What’s really going on? We’re doing repeated multiplications, and we’re keeping track of the running product. This algorithm is known as an accumulator, because we’re building up or accumulating the answer in a variable, known as the accumulator variable. Python Programming, 2/e
Accumulating Results: Factorial The general form of an accumulator algorithm looks like this: Initialize the accumulator variable Loop until final result is reached update the value of accumulator variable Python Programming, 2/e
Accumulating Results: Factorial It looks like we’ll need a loop! fact = 1 for factor in [6, 5, 4, 3, 2, 1]: fact = fact * factor Let’s trace through it to verify that this works! Python Programming, 2/e
Accumulating Results: Factorial Why did we need to initialize fact to 1? There are a couple reasons… Each time through the loop, the previous value of fact is used to calculate the next value of fact. By doing the initialization, you know fact will have a value the first time through. If you use fact without assigning it a value, what does Python do? Python Programming, 2/e
Accumulating Results: Factorial Since multiplication is associative and commutative, we can rewrite our program as: fact = 1 for factor in [2, 3, 4, 5, 6]: fact = fact * factor Great! But what if we want to find the factorial of some other number?? Python Programming, 2/e
Accumulating Results: Factorial What does range(n) return? 0, 1, 2, 3, …, n-1 range has another optional parameter! range(start, n) returns start, start + 1, …, n-1 But wait! There’s more! range(start, n, step) start, start+step, …, n-1 list(<sequence>) to make a list Python Programming, 2/e
Accumulating Results: Factorial Let’s try some examples! >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> list(range(5,10)) [5, 6, 7, 8, 9] >>> list(range(5,10,2)) [5, 7, 9] Python Programming, 2/e
Accumulating Results: Factorial Using this souped-up range statement, we can do the range for our loop a couple different ways. We can count up from 2 to n: range(2, n+1) (Why did we have to use n+1?) We can count down from n to 2: range(n, 1, -1) Python Programming, 2/e
Accumulating Results: Factorial Our completed factorial program: # factorial.py # Program to compute the factorial of a number # Illustrates for loop with an accumulator def main(): n = eval(input("Please enter a whole number: ")) fact = 1 for factor in range(n,1,-1): fact = fact * factor print("The factorial of", n, "is", fact) main() Python Programming, 2/e
The Limits of Int What is 100!? Wow! That’s a pretty big number! >>> main() Please enter a whole number: 100 The factorial of 100 is 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 Wow! That’s a pretty big number! Python Programming, 2/e
The Limits of Int Newer versions of Python can handle it, but… Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>> import fact >>> fact.main() Please enter a whole number: 13 13 12 11 10 9 8 7 6 5 4 Traceback (innermost last): File "<pyshell#1>", line 1, in ? fact.main() File "C:\PROGRA~1\PYTHON~1.2\fact.py", line 5, in main fact=fact*factor OverflowError: integer multiplication Python Programming, 2/e
The Limits of Int What’s going on? While there are an infinite number of integers, there is a finite range of ints that can be represented. This range depends on the number of bits a particular CPU uses to represent an integer value. Typical PCs use 32 bits. Python Programming, 2/e
The Limits of Int Typical PCs use 32 bits That means there are 232 possible values, centered at 0. This range then is –231 to 231-1. We need to subtract one from the top end to account for 0. But our 100! is much larger than this. How does it work? Python Programming, 2/e
Handling Large Numbers Does switching to float data types get us around the limitations of ints? If we initialize the accumulator to 1.0, we get >>> main() Please enter a whole number: 15 The factorial of 15 is 1.307674368e+012 We no longer get an exact answer! Python Programming, 2/e
Handling Large Numbers: Long Int Very large and very small numbers are expressed in scientific or exponential notation. 1.307674368e+012 means 1.307674368 * 1012 Here the decimal needs to be moved right 12 decimal places to get the original number, but there are only 9 digits, so 3 digits of precision have been lost. Python Programming, 2/e
Handling Large Numbers Floats are approximations Floats allow us to represent a larger range of values, but with lower precision. Python has a solution, expanding ints! Python Ints are not a fixed size and expand to handle whatever value it holds. Python Programming, 2/e
Handling Large Numbers Newer versions of Python automatically convert your ints to expanded form when they grow so large as to overflow. We get indefinitely large values (e.g. 100!) at the cost of speed and memory Python Programming, 2/e
Type Conversions We know that combining an int with an int produces an int, and combining a float with a float produces a float. What happens when you mix an int and float in an expression? x = 5.0 + 2 What do you think should happen? Python Programming, 2/e
Type Conversions For Python to evaluate this expression, it must either convert 5.0 to 5 and do an integer addition, or convert 2 to 2.0 and do a floating point addition. Converting a float to an int will lose information Ints can be converted to floats by adding “.0” Python Programming, 2/e
Type Conversion In mixed-typed expressions Python will convert ints to floats. Sometimes we want to control the type conversion. This is called explicit typing. Python Programming, 2/e
Type Conversions >>> float(22//5) 4.0 >>> int(4.5) 4 3 >>> round(3.9) >>> round(3) Python Programming, 2/e
Python Programming: An Introduction to Computer Science Chapter 4 Objects and Graphics Python Programming, 2/e 136 Python Programming, 1/e
Objectives To understand the concept of objects and how they can be used to simplify programs. To be familiar with the various objects available in the graphics library. To be able to create objects in programs and call appropriate methods to perform graphical computations. Python Programming, 2/e 137 Python Programming, 1/e
Objectives (cont.) To understand the fundamental concepts of computer graphics, especially the role of coordinate systems and coordinate transformations. To understand how to work with both mouse and text-based input in a graphical programming context. Python Programming, 2/e 138 Python Programming, 1/e
Objectives (cont.) To be able to write simple interactive graphics programs using the graphics library. Python Programming, 2/e 139 Python Programming, 1/e
Overview Each data type can represent a certain set of values, and each had a set of associated operations. The traditional programming view is that data is passive – it’s manipulated and combined with active operations. Python Programming, 2/e 140 Python Programming, 1/e
Overview Modern computer programs are built using an object-oriented approach. Most applications you’re familiar with have Graphical User Interfaces (GUI) that provide windows, icons, buttons and menus. There’s a graphics library (graphics.py) written specifically to go with this book. It’s based on Tkinter. Python Programming, 2/e 141 Python Programming, 1/e
The Object of Objects Basic idea – view a complex system as the interaction of simpler objects. An object is a sort of active data type that combines data and operations. Objects know stuff (contain data) and they can do stuff (have operations). Objects interact by sending each other messages. Python Programming, 2/e 142 Python Programming, 1/e
The Object of Objects Suppose we want to develop a data processing system for a college or university. We must keep records on students who attend the school. Each student will be represented as an object. Python Programming, 2/e 143 Python Programming, 1/e
The Object of Objects The student object would contain data like: Name ID number Courses taken Campus Address Home Address GPA Etc. Python Programming, 2/e 144 Python Programming, 1/e
The Object of Objects The student object should also respond to requests. We may want to send out a campus-wide mailing, so we’d need a campus address for each student. We could send the printCampusAddress to each student object. When the student object receives the message, it prints its own address. Python Programming, 2/e 145 Python Programming, 1/e
Object of Objects Instructor Student roster Prerequisite courses Objects may refer to other objects. Each course might be represented by an object: Instructor Student roster Prerequisite courses When and where the class meets Python Programming, 2/e 146 Python Programming, 1/e
Object of Objects addStudent delStudent changeRoom Etc. Sample Operation addStudent delStudent changeRoom Etc. Python Programming, 2/e 147 Python Programming, 1/e
Simple Graphics Programming This chapter uses the graphics.py library supplied with the supplemental materials. Two location choices In Python’s Lib directory with other libraries In the same folder as your graphics program Python Programming, 2/e 148 Python Programming, 1/e
Simple Graphics Programming Since this is a library, we need to import the graphics commands >>> import graphics A graphics window is a place on the screen where the graphics will appear. >>> win = graphics.GraphWin() This command creates a new window titled “Graphics Window.” Python Programming, 2/e 149 Python Programming, 1/e
Simple Graphics Programming GraphWin is an object assigned to the variable win. We can manipulate the window object through this variable, similar to manipulating files through file variables. Windows can be closed/destroyed by issuing the command >>> win.close() Python Programming, 2/e 150 Python Programming, 1/e
Simple Graphics Programming It’s tedious to use the graphics. notation to access the graphics library routines. from graphics import * The “from” statement allows you to load specific functions from a library module. “*” will load all the functions, or you can list specific ones. Python Programming, 2/e 151 Python Programming, 1/e
Simple Graphics Programming Doing the import this way eliminates the need to preface graphics commands with graphics. >>> from graphics import * >>> win = GraphWin() Python Programming, 2/e 152 Python Programming, 1/e
Simple Graphics Programming A graphics window is a collection of points called pixels (picture elements). The default GraphWin is 200 pixels tall by 200 pixels wide (40,000 pixels total). One way to get pictures into the window is one pixel at a time, which would be tedious. The graphics routine has a number of predefined routines to draw geometric shapes. Python Programming, 2/e 153 Python Programming, 1/e Python Programming, 1/e 153
Simple Graphics Programming The simplest object is the Point. Like points in geometry, point locations are represented with a coordinate system (x, y), where x is the horizontal location of the point and y is the vertical location. The origin (0,0) in a graphics window is the upper left corner. X values increase from left to right, y values from top to bottom. Lower right corner is (199, 199) Python Programming, 2/e 154 Python Programming, 1/e
Simple Graphics Programming >>> p = Point(50, 60) >>> p.getX() 50 >>> p.getY() 60 >>> win = GraphWin() >>> p.draw(win) >>> p2 = Point(140, 100) >>> p2.draw(win) Python Programming, 2/e 155 Python Programming, 1/e
Simple Graphics Programming >>> ### Open a graphics window >>> win = GraphWin('Shapes') >>> ### Draw a red circle centered at point (100, 100) with radius 30 >>> center = Point(100, 100) >>> circ = Circle(center, 30) >>> circ.setFill('red') >>> circ.draw(win) >>> ### Put a textual label in the center of the circle >>> label = Text(center, "Red Circle") >>> label.draw(win) >>> ### Draw a square using a Rectangle object >>> rect = Rectangle(Point(30, 30), Point(70, 70)) >>> rect.draw(win) >>> ### Draw a line segment using a Line object >>> line = Line(Point(20, 30), Point(180, 165)) >>> line.draw(win) >>> ### Draw an oval using the Oval object >>> oval = Oval(Point(20, 150), Point(180, 199)) >>> oval.draw(win) Python Programming, 2/e 156 Python Programming, 1/e
Using Graphical Objects Computation is preformed by asking an object to carry out one of its operations. In the previous example we manipulated GraphWin, Point, Circle, Oval, Line, Text and Rectangle. These are examples of classes. Python Programming, 2/e 157 Python Programming, 1/e
Using Graphical Objects Each object is an instance of some class, and the class describes the properties of the instance. If we say that Augie is a dog, we are actually saying that Augie is a specific individual in the larger class of all dogs. Augie is an instance of the dog class. Python Programming, 2/e 158 Python Programming, 1/e
Using Graphical Objects To create a new instance of a class, we use a special operation called a constructor. <class-name>(<param1>, <param2>, …) <class-name> is the name of the class we want to create a new instance of, e.g. Circle or Point. The parameters are required to initialize the object. For example, Point requires two numeric values. Python Programming, 2/e 159 Python Programming, 1/e
Using Graphical Objects p = Point(50, 60) The constructor for the Point class requires to parameters, the x and y coordinates for the point. These values are stored as instance variables inside of the object. Python Programming, 2/e 160 Python Programming, 1/e
Using Graphical Objects Only the most relevant instance variables are shown (others include the color, window they belong to, etc.) Python Programming, 2/e 161 Python Programming, 1/e
Using Graphical Objects To perform an operation on an object, we send the object a message. The set of messages an object responds to are called the methods of the object. Methods are like functions that live inside the object. Methods are invoked using dot-notation: <object>.<method-name>(<param1>, <param2>, …) Python Programming, 2/e 162 Python Programming, 1/e
Using Graphical Objects p.getX() and p.getY() returns the x and y values of the point. Routines like these are referred to as accessors because they allow us to access information from the instance variables of the object. Python Programming, 2/e 163 Python Programming, 1/e
Using Graphical Objects Other methods change the state of the object by changing the values of the object’s instance variables. move(dx, dy) moves the object dx units in the x direction and dy in the y direction. Move erases the old image and draws it in its new position. Methods that change the state of an object are called mutators. Python Programming, 2/e 164 Python Programming, 1/e
Using Graphical Objects >>> circ = Circle(Point(100, 100), 30) >>> win = GraphWin() >>> circ.draw(win) The first line creates a circle with radius 30 centered at (100,100). We used the Point constructor to create a location for the center of the circle. The last line is a request to the Circle object circ to draw itself into the GraphWin object win. Python Programming, 2/e 165 Python Programming, 1/e
Using Graphical Objects The draw method uses information about the center and radius of the circle from the instance variable. Python Programming, 2/e 166 Python Programming, 1/e
Using Graphical Objects It’s possible for two different variables to refer to the same object – changes made to the object through one variable will be visible to the other. >>> leftEye = Circle(Point(80,50), 5) >>> leftEye.setFill('yellow') >>> leftEye.setOutline('red') >>> rightEye = leftEye >>> rightEye.move(20,0) The idea is to create the left eye and copy that to the right eye which gets moved 20 units. Python Programming, 2/e 167 Python Programming, 1/e
Using Graphical Objects The assignment rightEye = leftEye makes rightEye and leftEye refer to the same circle! The situation where two variables refer to the same object is called aliasing. Python Programming, 2/e 168 Python Programming, 1/e
Using Graphical Objects Python Programming, 2/e 169 Python Programming, 1/e
Using Graphical Objects There are two ways to get around this. We could make two separate circles, one for each eye: >>> leftEye = Circle(Point(80, 50), 5) >>> leftEye.setFill('yellow') >>> leftEye.setOutline('red') >>> rightEye = Circle(Point(100, 50), 5) >>> rightEye.setFill('yellow') >>> rightEye.setOutline('red') Python Programming, 2/e 170 Python Programming, 1/e
Using Graphical Objects The graphics library has a better solution. Graphical objects have a clone method that will make a copy of the object! >>> # Correct way to create two circles, using clone >>> leftEye = Circle(Point(80, 50), 5) >>> leftEye.setFill('yellow') >>> leftEye.setOutline('red') >>> rightEye = leftEye.clone() # rightEye is an exact copy of the left >>> rightEye.move(20, 0) Python Programming, 2/e 171 Python Programming, 1/e
Graphing Future Value/ Choosing Coordinates Python Programming, 2/e 172 Python Programming, 1/e
Graphing Future Value/ Choosing Coordinates Python Programming, 2/e 173 Python Programming, 1/e
Interactive Graphics In a GUI environment, users typically interact with their applications by clicking on buttons, choosing items from menus, and typing information into on- screen text boxes. Event-driven programming draws interface elements (widgets) on the screen and then waits for the user to do something. Python Programming, 2/e 174 Python Programming, 1/e
Interactive Graphics An event is generated whenever a user moves the mouse, clicks the mouse, or types a key on the keyboard. An event is an object that encapsulates information about what just happened! The event object is sent to the appropriate part of the program to be processed, for example, a button event. Python Programming, 2/e 175 Python Programming, 1/e
Interactive Graphics The graphics module hides the underlying, low-level window management and provides two simple ways to get user input in a GraphWin. Python Programming, 2/e 176 Python Programming, 1/e
Getting Mouse Clicks We can get graphical information from the user via the getMouse method of the GraphWin class. When getMouse is invoked on a GraphWin, the program pauses and waits for the user to click the mouse somewhere in the window. The spot where the user clicked is returned as a Point. Python Programming, 2/e 177 Python Programming, 1/e
Getting Mouse Clicks The following code reports the coordinates of a mouse click: from graphics import * win = GraphWin("Click Me!") p = win.getMouse() print("You clicked", p.getX(), p.getY()) We can use the accessors like getX and getY or other methods on the point returned. Python Programming, 2/e 178 Python Programming, 1/e
Getting Mouse Clicks # triangle.pyw # Interactive graphics program to draw a triangle from graphics import * def main(): win = GraphWin("Draw a Triangle") win.setCoords(0.0, 0.0, 10.0, 10.0) message = Text(Point(5, 0.5), "Click on three points") message.draw(win) # Get and draw three vertices of triangle p1 = win.getMouse() p1.draw(win) p2 = win.getMouse() p2.draw(win) p3 = win.getMouse() p3.draw(win) Python Programming, 2/e 179 Python Programming, 1/e
Getting Mouse Clicks # Use Polygon object to draw the triangle triangle = Polygon(p1,p2,p3) triangle.setFill("peachpuff") triangle.setOutline("cyan") triangle.draw(win) # Wait for another click to exit message.setText("Click anywhere to quit.") win.getMouse() main() Python Programming, 2/e 180 Python Programming, 1/e
Getting Mouse Clicks Python Programming, 2/e 181
Getting Mouse Clicks Notes: If you are programming in a windows environment, using the .pyw extension on your file will cause the Python shell window to not display when you double-click the program icon. There is no triangle class. Rather, we use the general polygon class, which takes any number of points and connects them into a closed shape. Python Programming, 2/e 182 Python Programming, 1/e
Getting Mouse Clicks Once you have three points, creating a triangle polygon is easy: triangle = Polygon(p1, p2, p3) A single text object is created and drawn near the beginning of the program. message = Text(Point(5,0.5), "Click on three points") message.draw(win) To change the prompt, just change the text to be displayed. message.setText("Click anywhere to quit.") Python Programming, 2/e 183 Python Programming, 1/e
Handling Textual Input The triangle program’s input was done completely through mouse clicks. There’s also an Entry object that can get keyboard input. The Entry object draws a box on the screen that can contain text. It understands setText and getText, with one difference that the input can be edited. Python Programming, 2/e 184 Python Programming, 1/e
Handling Textual Input Python Programming, 2/e 185 Python Programming, 1/e
Handling Textual Input # convert_gui.pyw # Program to convert Celsius to Fahrenheit using a simple # graphical interface. from graphics import * def main(): win = GraphWin("Celsius Converter", 300, 200) win.setCoords(0.0, 0.0, 3.0, 4.0) # Draw the interface Text(Point(1,3), " Celsius Temperature:").draw(win) Text(Point(1,1), "Fahrenheit Temperature:").draw(win) input = Entry(Point(2,3), 5) input.setText("0.0") input.draw(win) output = Text(Point(2,1),"") output.draw(win) button = Text(Point(1.5,2.0),"Convert It") button.draw(win) Rectangle(Point(1,1.5), Point(2,2.5)).draw(win) Python Programming, 2/e 186 Python Programming, 1/e
Handling Textual Input # wait for a mouse click win.getMouse() # convert input celsius = eval(input.getText()) fahrenheit = 9.0/5.0 * celsius + 32 # display output and change button output.setText(fahrenheit) button.setText("Quit") # wait for click and then quit win.close() main() Python Programming, 2/e 187 Python Programming, 1/e
Handling Textual Input Python Programming, 2/e 188 Python Programming, 1/e
Handling Textual Input When run, this program produces a window with an entry box for typing in the Celsius temperature and a button to “do” the conversion. The button is for show only! We are just waiting for a mouse click anywhere in the window. Python Programming, 2/e 189 Python Programming, 1/e
Handling Textual Input Initially, the input entry box is set to contain “0.0”. The user can delete this value and type in another value. The program pauses until the user clicks the mouse – we don’t care where so we don’t store the point! Python Programming, 2/e 190 Python Programming, 1/e
Handling Textual Input The input is processed in three steps: The value entered is converted into a number with eval. This number is converted to degrees Fahrenheit. This number is then converted to a string and formatted for display in the output text area. Python Programming, 2/e 191 Python Programming, 1/e
Python Programming: An Introduction to Computer Science Chapter 5 Sequences: Strings, Lists, and Files Python Programming, 2/e
Objectives To understand the string data type and how strings are represented in the computer. To be familiar with various operations that can be performed on strings through built-in functions and the string library. Python Programming, 2/e
Objectives (cont.) To understand the basic idea of sequences and indexing as they apply to Python strings and lists. To be able to apply string formatting to produce attractive, informative program output. To understand basic file processing concepts and techniques for reading and writing text files in Python. Python Programming, 2/e
Objectives (cont.) To understand basic concepts of cryptography. To be able to understand and write programs that process textual information. Python Programming, 2/e
The String Data Type The most common use of personal computers is word processing. Text is represented in programs by the string data type. A string is a sequence of characters enclosed within quotation marks (") or apostrophes ('). Python Programming, 2/e
The String Data Type >>> str1="Hello" >>> str2='spam' >>> print(str1, str2) Hello spam >>> type(str1) <class 'str'> >>> type(str2) Python Programming, 2/e
The String Data Type Getting a string as input >>> firstName = input("Please enter your name: ") Please enter your name: John >>> print("Hello", firstName) Hello John Notice that the input is not evaluated. We want to store the typed characters, not to evaluate them as a Python expression. Python Programming, 2/e
The String Data Type We can access the individual characters in a string through indexing. The positions in a string are numbered from the left, starting with 0. The general form is <string>[<expr>], where the value of expr determines which character is selected from the string. Python Programming, 2/e
The String Data Type H e l o B b 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 >>> greet = "Hello Bob" >>> greet[0] 'H' >>> print(greet[0], greet[2], greet[4]) H l o >>> x = 8 >>> print(greet[x - 2]) B Python Programming, 2/e
The String Data Type H e l o B b 0 1 2 3 4 5 6 7 8 In a string of n characters, the last character is at position n-1 since we start counting with 0. We can index from the right side using negative indexes. >>> greet[-1] 'b' >>> greet[-3] 'B' Python Programming, 2/e
The String Data Type Indexing returns a string containing a single character from a larger string. We can also access a contiguous sequence of characters, called a substring, through a process called slicing. Python Programming, 2/e
The String Data Type Slicing: <string>[<start>:<end>] start and end should both be ints The slice contains the substring beginning at position start and runs up to but doesn’t include the position end. Python Programming, 2/e
The String Data Type H e l o B b 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 >>> greet[0:3] 'Hel' >>> greet[5:9] ' Bob' >>> greet[:5] 'Hello' >>> greet[5:] >>> greet[:] 'Hello Bob' Python Programming, 2/e
The String Data Type If either expression is missing, then the start or the end of the string are used. Can we put two strings together into a longer string? Concatenation “glues” two strings together (+) Repetition builds up a string by multiple concatenations of a string with itself (*) Python Programming, 2/e
The String Data Type The function len will return the length of a string. >>> "spam" + "eggs" 'spameggs' >>> "Spam" + "And" + "Eggs" 'SpamAndEggs' >>> 3 * "spam" 'spamspamspam' >>> "spam" * 5 'spamspamspamspamspam' >>> (3 * "spam") + ("eggs" * 5) 'spamspamspameggseggseggseggseggs' Python Programming, 2/e
The String Data Type >>> len("spam") 4 >>> for ch in "Spam!": print (ch, end=" ") S p a m ! Python Programming, 2/e
The String Data Type Operator Meaning + Concatenation * Repetition Indexing <string>[:] Slicing len(<string>) Length for <var> in <string> Iteration through characters Python Programming, 2/e
Simple String Processing Usernames on a computer system First initial, first seven characters of last name # get user’s first and last names first = input("Please enter your first name (all lowercase): ") last = input("Please enter your last name (all lowercase): ") # concatenate first initial with 7 chars of last name uname = first[0] + last[:7] Python Programming, 2/e
Simple String Processing >>> Please enter your first name (all lowercase): john Please enter your last name (all lowercase): doe uname = jdoe Please enter your first name (all lowercase): donna Please enter your last name (all lowercase): rostenkowski uname = drostenk Python Programming, 2/e
Simple String Processing Another use – converting an int that stands for the month into the three letter abbreviation for that month. Store all the names in one big string: “JanFebMarAprMayJunJulAugSepOctNovDec” Use the month number as an index for slicing this string: monthAbbrev = months[pos:pos+3] Python Programming, 2/e
Simple String Processing Month Number Position Jan 1 Feb 2 3 Mar 6 Apr 4 9 To get the correct position, subtract one from the month number and multiply by three Python Programming, 2/e
Simple String Processing # month.py # A program to print the abbreviation of a month, given its number def main(): # months is used as a lookup table months = "JanFebMarAprMayJunJulAugSepOctNovDec" n = eval(input("Enter a month number (1-12): ")) # compute starting position of month n in months pos = (n-1) * 3 # Grab the appropriate slice from months monthAbbrev = months[pos:pos+3] # print the result print ("The month abbreviation is", monthAbbrev + ".") main() Python Programming, 2/e
Simple String Processing >>> main() Enter a month number (1-12): 1 The month abbreviation is Jan. Enter a month number (1-12): 12 The month abbreviation is Dec. One weakness – this method only works where the potential outputs all have the same length. How could you handle spelling out the months? Python Programming, 2/e
Strings, Lists, and Sequences It turns out that strings are really a special kind of sequence, so these operations also apply to sequences! >>> [1,2] + [3,4] [1, 2, 3, 4] >>> [1,2]*3 [1, 2, 1, 2, 1, 2] >>> grades = ['A', 'B', 'C', 'D', 'F'] >>> grades[0] 'A' >>> grades[2:4] ['C', 'D'] >>> len(grades) 5 Python Programming, 2/e
Strings, Lists, and Sequences Strings are always sequences of characters, but lists can be sequences of arbitrary values. Lists can have numbers, strings, or both! myList = [1, "Spam ", 4, "U"] Python Programming, 2/e
Strings, Lists, and Sequences We can use the idea of a list to make our previous month program even simpler! We change the lookup table for months to a list: months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] Python Programming, 2/e
Strings, Lists, and Sequences To get the months out of the sequence, do this: monthAbbrev = months[n-1] Rather than this: monthAbbrev = months[pos:pos+3] Python Programming, 2/e
Strings, Lists, and Sequences # month2.py # A program to print the month name, given it's number. # This version uses a list as a lookup table. def main(): # months is a list used as a lookup table months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] n = eval(input("Enter a month number (1-12): ")) print ("The month abbreviation is", months[n-1] + ".") main() Note that the months line overlaps a line. Python knows that the expression isn’t complete until the closing ] is encountered. Python Programming, 2/e
Strings, Lists, and Sequences # month2.py # A program to print the month name, given it's number. # This version uses a list as a lookup table. def main(): # months is a list used as a lookup table months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] n = eval(input("Enter a month number (1-12): ")) print ("The month abbreviation is", months[n-1] + ".") main() Since the list is indexed starting from 0, the n-1 calculation is straight-forward enough to put in the print statement without needing a separate step. Python Programming, 2/e
Strings, Lists, and Sequences This version of the program is easy to extend to print out the whole month name rather than an abbreviation! months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] Python Programming, 2/e
Strings, Lists, and Sequences Lists are mutable, meaning they can be changed. Strings can not be changed. >>> myList = [34, 26, 15, 10] >>> myList[2] 15 >>> myList[2] = 0 >>> myList [34, 26, 0, 10] >>> myString = "Hello World" >>> myString[2] 'l' >>> myString[2] = "p" Traceback (most recent call last): File "<pyshell#16>", line 1, in -toplevel- myString[2] = "p" TypeError: object doesn't support item assignment Python Programming, 2/e
Strings and Secret Codes Inside the computer, strings are represented as sequences of 1’s and 0’s, just like numbers. A string is stored as a sequence of binary numbers, one number per character. It doesn’t matter what value is assigned as long as it’s done consistently. Python Programming, 2/e
Strings and Secret Codes In the early days of computers, each manufacturer used their own encoding of numbers for characters. ASCII system (American Standard Code for Information Interchange) uses 127 bit codes Python supports Unicode (100,000+ characters) Python Programming, 2/e
Strings and Secret Codes The ord function returns the numeric (ordinal) code of a single character. The chr function converts a numeric code to the corresponding character. >>> ord("A") 65 >>> ord("a") 97 >>> chr(97) 'a' >>> chr(65) 'A' Python Programming, 2/e
Strings and Secret Codes Using ord and char we can convert a string into and out of numeric form. The encoding algorithm is simple: get the message to encode for each character in the message: print the letter number of the character A for loop iterates over a sequence of objects, so the for loop looks like: for ch in <string> Python Programming, 2/e
Strings and Secret Codes # text2numbers.py # A program to convert a textual message into a sequence of # numbers, utlilizing the underlying Unicode encoding. def main(): print("This program converts a textual message into a sequence") print ("of numbers representing the Unicode encoding of the message.\n") # Get the message to encode message = input("Please enter the message to encode: ") print("\nHere are the Unicode codes:") # Loop through the message and print out the Unicode values for ch in message: print(ord(ch), end=" ") print() main() Python Programming, 2/e
Strings and Secret Codes We now have a program to convert messages into a type of “code”, but it would be nice to have a program that could decode the message! The outline for a decoder: get the sequence of numbers to decode message = “” for each number in the input: convert the number to the appropriate character add the character to the end of the message print the message Python Programming, 2/e
Strings and Secret Codes The variable message is an accumulator variable, initially set to the empty string, the string with no characters (“”). Each time through the loop, a number from the input is converted to the appropriate character and appended to the end of the accumulator. Python Programming, 2/e
Strings and Secret Codes How do we get the sequence of numbers to decode? Read the input as a single string, then split it apart into substrings, each of which represents one number. Python Programming, 2/e
Strings and Secret Codes The new algorithm get the sequence of numbers as a string, inString message = “” for each of the smaller strings: change the string of digits into the number it represents append the ASCII character for that number to message print message Strings are objects and have useful methods associated with them Python Programming, 2/e
Strings and Secret Codes One of these methods is split. This will split a string into substrings based on spaces. >>> "Hello string methods!".split() ['Hello', 'string', 'methods!'] Python Programming, 2/e
Strings and Secret Codes Split can be used on characters other than space, by supplying the character as a parameter. >>> "32,24,25,57".split(",") ['32', '24', '25', '57'] >>> Python Programming, 2/e
Strings and Secret Codes How can we convert a string containing digits into a number? Use our friend eval. >>> numStr = "500" >>> eval(numStr) 500 >>> x = eval(input("Enter a number ")) Enter a number 3.14 >>> print x 3.14 >>> type (x) <type 'float'> Python Programming, 2/e
Strings and Secret Codes # numbers2text.py # A program to convert a sequence of Unicode numbers into # a string of text. def main(): print ("This program converts a sequence of Unicode numbers into") print ("the string of text that it represents.\n") # Get the message to encode inString = input("Please enter the Unicode-encoded message: ") # Loop through each substring and build Unicde message message = "" for numStr in inString.split(i): # convert the (sub)string to a number codeNum = eval(numStr) # append character to message message = message + chr(codeNum) print("\nThe decoded message is:", message) main() Python Programming, 2/e
Strings and Secret Codes The split function produces a sequence of strings. numString gets each successive substring. Each time through the loop, the next substring is converted to the appropriate Unicode character and appended to the end of message. Python Programming, 2/e
Strings and Secret Codes ------------------------------------------------------------------------- This program converts a textual message into a sequence of numbers representing the Unicode encoding of the message. Please enter the message to encode: CS120 is fun! Here are the Unicode codes: 67 83 49 50 48 32 105 115 32 102 117 110 33 -------------------------------------------------------------------------- This program converts a sequence of Unicode numbers into the string of text that it represents. Please enter the ASCII-encoded message: 67 83 49 50 48 32 105 115 32 102 117 110 33 The decoded message is: CS120 is fun! Python Programming, 2/e
Other String Methods There are a number of other string methods. Try them all! s.capitalize() – Copy of s with only the first character capitalized s.title() – Copy of s; first character of each word capitalized s.center(width) – Center s in a field of given width Python Programming, 2/e
Other String Operations s.count(sub) – Count the number of occurrences of sub in s s.find(sub) – Find the first position where sub occurs in s s.join(list) – Concatenate list of strings into one large string using s as separator. s.ljust(width) – Like center, but s is left-justified Python Programming, 2/e
Other String Operations s.lower() – Copy of s in all lowercase letters s.lstrip() – Copy of s with leading whitespace removed s.replace(oldsub, newsub) – Replace occurrences of oldsub in s with newsub s.rfind(sub) – Like find, but returns the right-most position s.rjust(width) – Like center, but s is right-justified Python Programming, 2/e
Other String Operations s.rstrip() – Copy of s with trailing whitespace removed s.split() – Split s into a list of substrings s.upper() – Copy of s; all characters converted to uppercase Python Programming, 2/e
From Encoding to Encryption The process of encoding information for the purpose of keeping it secret or transmitting it privately is called encryption. Cryptography is the study of encryption methods. Encryption is used when transmitting credit card and other personal information to a web site. Python Programming, 2/e
From Encoding to Encryption Strings are represented as a sort of encoding problem, where each character in the string is represented as a number that’s stored in the computer. The code that is the mapping between character and number is an industry standard, so it’s not “secret”. Python Programming, 2/e
From Encoding to Encryption The encoding/decoding programs we wrote use a substitution cipher, where each character of the original message, known as the plaintext, is replaced by a corresponding symbol in the cipher alphabet. The resulting code is known as the ciphertext. Python Programming, 2/e
From Encoding to Encryption This type of code is relatively easy to break. Each letter is always encoded with the same symbol, so using statistical analysis on the frequency of the letters and trial and error, the original message can be determined. Python Programming, 2/e
From Encoding to Encryption Modern encryption converts messages into numbers. Sophisticated mathematical formulas convert these numbers into new numbers – usually this transformation consists of combining the message with another value called the “key” Python Programming, 2/e
From Encoding to Encryption To decrypt the message, the receiving end needs an appropriate key so the encoding can be reversed. In a private key system the same key is used for encrypting and decrypting messages. Everyone you know would need a copy of this key to communicate with you, but it needs to be kept a secret. Python Programming, 2/e
From Encoding to Encryption In public key encryption, there are separate keys for encrypting and decrypting the message. In public key systems, the encryption key is made publicly available, while the decryption key is kept private. Anyone with the public key can send a message, but only the person who holds the private key (decryption key) can decrypt it. Python Programming, 2/e
Input/Output as String Manipulation Often we will need to do some string operations to prepare our string data for output (“pretty it up”) Let’s say we want to enter a date in the format “05/24/2003” and output “May 24, 2003.” How could we do that? Python Programming, 2/e
Input/Output as String Manipulation Input the date in mm/dd/yyyy format (dateStr) Split dateStr into month, day, and year strings Convert the month string into a month number Use the month number to lookup the month name Create a new date string in the form “Month Day, Year” Output the new date string Python Programming, 2/e
Input/Output as String Manipulation The first two lines are easily implemented! dateStr = input("Enter a date (mm/dd/yyyy): ") monthStr, dayStr, yearStr = dateStr.split("/") The date is input as a string, and then “unpacked” into the three variables by splitting it at the slashes and using simultaneous assignment. Python Programming, 2/e
Input/Output as String Manipulation Next step: Convert monthStr into a number We can use the int function on monthStr to convert "05", for example, into the integer 5. (int("05") = 5) Python Programming, 2/e
Input/Output as String Manipulation Note: eval would work, but for the leading 0 >>> int("05") 5 >>> eval("05") Traceback (most recent call last): File "<pyshell#9>", line 1, in <module> eval("05") File "<string>", line 1 05 ^ SyntaxError: invalid token This is historical baggage. A leading 0 used to be used for base 8 (octal) literals in Python. Python Programming, 2/e
Input/Output as String Manipulation months = [“January”, “February”, …, “December”] monthStr = months[int(monthStr) – 1] Remember that since we start counting at 0, we need to subtract one from the month. Now let’s concatenate the output string together! Python Programming, 2/e
Input/Output as String Manipulation print ("The converted date is:", monthStr, dayStr+",", yearStr) Notice how the comma is appended to dayStr with concatenation! >>> main() Enter a date (mm/dd/yyyy): 01/23/2010 The converted date is: January 23, 2010 Python Programming, 2/e
Input/Output as String Manipulation Sometimes we want to convert a number into a string. We can use the str function. >>> str(500) '500' >>> value = 3.14 >>> str(value) '3.14' >>> print("The value is", str(value) + ".") The value is 3.14. Python Programming, 2/e
Input/Output as String Manipulation If value is a string, we can concatenate a period onto the end of it. If value is an int, what happens? >>> value = 3.14 >>> print("The value is", value + ".") The value is Traceback (most recent call last): File "<pyshell#10>", line 1, in -toplevel- print "The value is", value + "." TypeError: unsupported operand type(s) for +: 'float' and 'str' Python Programming, 2/e
Input/Output as String Manipulation We now have a complete set of type conversion operations: Function Meaning float(<expr>) Convert expr to a floating point value int(<expr>) Convert expr to an integer value str(<expr>) Return a string representation of expr eval(<string>) Evaluate string as an expression Python Programming, 2/e
String Formatting String formatting is an easy way to get beautiful output! Change Counter Please enter the count of each coin type. Quarters: 6 Dimes: 0 Nickels: 0 Pennies: 0 The total value of your change is 1.5 Shouldn’t that be more like $1.50?? Python Programming, 2/e
String Formatting We can format our output by modifying the print statement as follows: print("The total value of your change is ${0:0.2f}".format(total)) Now we get something like: The total value of your change is $1.50 Key is the string format method. Python Programming, 2/e
String Formatting <template-string>.format(<values>) {} within the template-string mark “slots” into which the values are inserted. Each slot has description that includes format specifier telling Python how the value for the slot should appear. Python Programming, 2/e
String Formatting print("The total value of your change is ${0:0.2f}".format(total) The template contains a single slot with the description: 0:0.2f Form of description: <index>:<format-specifier> Index tells which parameter to insert into the slot. In this case, total. Python Programming, 2/e
String Formatting The formatting specifier has the form: <width>.<precision><type> f means "fixed point" number <width> tells us how many spaces to use to display the value. 0 means to use as much space as necessary. <precision> is the number of decimal places. Python Programming, 2/e
String Formatting >>> "Hello {0} {1}, you may have won ${2}" .format("Mr.", "Smith", 10000) 'Hello Mr. Smith, you may have won $10000' >>> 'This int, {0:5}, was placed in a field of width 5'.format(7) 'This int, 7, was placed in a field of width 5' >>> 'This int, {0:10}, was placed in a field of witdh 10'.format(10) 'This int, 10, was placed in a field of witdh 10' >>> 'This float, {0:10.5}, has width 10 and precision 5.'.format(3.1415926) 'This float, 3.1416, has width 10 and precision 5.' >>> 'This float, {0:10.5f}, is fixed at 5 decimal places.'.format(3.1415926) 'This float, 3.14159, has width 0 and precision 5.' Python Programming, 2/e
String Formatting If the width is wider than needed, numeric values are right-justified and strings are left- justified, by default. You can also specify a justification before the width. >>> "left justification: {0:<5}.format("Hi!") 'left justification: Hi! ' >>> "right justification: {0:>5}.format("Hi!") 'right justification: Hi!' >>> "centered: {0:^5}".format("Hi!") 'centered: Hi! ' Python Programming, 2/e
Better Change Counter With what we know now about floating point numbers, we might be uneasy about using them in a money situation. One way around this problem is to keep trace of money in cents using an int or long int, and convert it into dollars and cents when output. Python Programming, 2/e
Better Change Counter If total is a value in cents (an int), dollars = total//100 cents = total%100 Cents is printed using width 0>2 to right-justify it with leading 0s (if necessary) into a field of width 2. Thus 5 cents becomes '05' Python Programming, 2/e
Better Change Counter # change2.py # A program to calculate the value of some change in dollars. # This version represents the total cash in cents. def main(): print ("Change Counter\n") print ("Please enter the count of each coin type.") quarters = eval(input("Quarters: ")) dimes = eval(input("Dimes: ")) nickels = eval(input("Nickels: ")) pennies = eval(input("Pennies: ")) total = quarters * 25 + dimes * 10 + nickels * 5 + pennies print ("The total value of your change is ${0}.{1:0>2}" .format(total//100, total%100)) Python Programming, 2/e
Better Change Counter >>> main() Change Counter Please enter the count of each coin type. Quarters: 0 Dimes: 0 Nickels: 0 Pennies: 1 The total value of your change is $0.01 >>> main() Change Counter Please enter the count of each coin type. Quarters: 12 Dimes: 1 Nickels: 0 Pennies: 4 The total value of your change is $3.14 Python Programming, 2/e
Files: Multi-line Strings A file is a sequence of data that is stored in secondary memory (disk drive). Files can contain any data type, but the easiest to work with are text. A file usually contains more than one line of text. Python uses the standard newline character (\n) to mark line breaks. Python Programming, 2/e
Multi-Line Strings Hello World Goodbye 32 When stored in a file: Hello\nWorld\n\nGoodbye 32\n Python Programming, 2/e
Multi-Line Strings This is exactly the same thing as embedding \n in print statements. Remember, these special characters only affect things when printed. They don’t do anything during evaluation. Python Programming, 2/e
File Processing The process of opening a file involves associating a file on disk with an object in memory. We can manipulate the file by manipulating this object. Read from the file Write to the file Python Programming, 2/e
File Processing When done with the file, it needs to be closed. Closing the file causes any outstanding operations and other bookkeeping for the file to be completed. In some cases, not properly closing a file could result in data loss. Python Programming, 2/e
File Processing Reading a file into a word processor File opened Contents read into RAM File closed Changes to the file are made to the copy stored in memory, not on the disk. Python Programming, 2/e
File Processing Saving a word processing file The original file on the disk is reopened in a mode that will allow writing (this actually erases the old contents) File writing operations copy the version of the document in memory to the disk The file is closed Python Programming, 2/e
File Processing Working with text files in Python Associate a disk file with a file object using the open function <filevar> = open(<name>, <mode>) Name is a string with the actual file name on the disk. The mode is either ‘r’ or ‘w’ depending on whether we are reading or writing the file. Infile = open("numbers.dat", "r") Python Programming, 2/e
File Methods <file>.read() – returns the entire remaining contents of the file as a single (possibly large, multi-line) string <file>.readline() – returns the next line of the file. This is all text up to and including the next newline character <file>.readlines() – returns a list of the remaining lines in the file. Each list item is a single line including the newline characters. Python Programming, 2/e
File Processing First, prompt the user for a file name # printfile.py # Prints a file to the screen. def main(): fname = input("Enter filename: ") infile = open(fname,'r') data = infile.read() print(data) main() First, prompt the user for a file name Open the file for reading The file is read as one string and stored in the variable data Python Programming, 2/e
File Processing readline can be used to read the next line from a file, including the trailing newline character infile = open(someFile, "r") for i in range(5): line = infile.readline() print line[:-1] This reads the first 5 lines of a file Slicing is used to strip out the newline characters at the ends of the lines Python Programming, 2/e
File Processing Another way to loop through the contents of a file is to read it in with readlines and then loop through the resulting list. infile = open(someFile, "r") for line in infile.readlines(): # Line processing here infile.close() Python Programming, 2/e
File Processing Python treats the file itself as a sequence of lines! Infile = open(someFile, "r") for line in infile: # process the line here infile.close() Python Programming, 2/e
File Processing Opening a file for writing prepares the file to receive data If you open an existing file for writing, you wipe out the file’s contents. If the named file does not exist, a new one is created. Outfile = open("mydata.out", "w") print(<expressions>, file=Outfile) Python Programming, 2/e
Example Program: Batch Usernames Batch mode processing is where program input and output are done through files (the program is not designed to be interactive) Let’s create usernames for a computer system where the first and last names come from an input file. Python Programming, 2/e
Example Program: Batch Usernames # userfile.py # Program to create a file of usernames in batch mode. def main(): print ("This program creates a file of usernames from a") print ("file of names.") # get the file names infileName = input("What file are the names in? ") outfileName = input("What file should the usernames go in? ") # open the files infile = open(infileName, 'r') outfile = open(outfileName, 'w') Python Programming, 2/e
Example Program: Batch Usernames # process each line of the input file for line in infile: # get the first and last names from line first, last = line.split() # create a username uname = (first[0]+last[:7]).lower() # write it to the output file print(uname, file=outfile) # close both files infile.close() outfile.close() print("Usernames have been written to", outfileName) Python Programming, 2/e
Example Program: Batch Usernames Things to note: It’s not unusual for programs to have multiple files open for reading and writing at the same time. The lower method is used to convert the names into all lower case, in the event the names are mixed upper and lower case. Python Programming, 2/e
Python Programming: An Introduction to Computer Science Chapter 6 Defining Functions Python Programming, 2/e
Objectives To understand why programmers divide programs up into sets of cooperating functions. To be able to define new functions in Python. To understand the details of function calls and parameter passing in Python. Python Programming, 2/e
Objectives (cont.) To write programs that use functions to reduce code duplication and increase program modularity. Python Programming, 2/e
The Function of Functions So far, we’ve seen four different types of functions: Our programs comprise a single function called main(). Built-in Python functions (abs) Functions from the standard libraries (math.sqrt) Functions from the graphics module (p.getX()) Python Programming, 2/e Python Programming, 1/e
The Function of Functions Having similar or identical code in more than one place has some drawbacks. Issue one: writing the same code twice or more. Issue two: This same code must be maintained in two separate places. Functions can be used to reduce code duplication and make programs more easily understood and maintained. Python Programming, 2/e
Functions, Informally A function is like a subprogram, a small program inside of a program. The basic idea – we write a sequence of statements and then give that sequence a name. We can then execute this sequence at any time by referring to the name. Python Programming, 2/e
Functions, Informally The part of the program that creates a function is called a function definition. When the function is used in a program, we say the definition is called or invoked. Python Programming, 2/e
Functions, Informally Happy Birthday lyrics… def main(): print("Happy birthday to you!" ) print("Happy birthday to you!" ) print("Happy birthday, dear Fred...") print("Happy birthday to you!") Gives us this… >>> main() Happy birthday to you! Happy birthday to you! Happy birthday, dear Fred... Happy birthday to you! Python Programming, 2/e
Functions, Informally There’s some duplicated code in the program! (print("Happy birthday to you!")) We can define a function to print out this line: def happy(): print("Happy birthday to you!") With this function, we can rewrite our program. Python Programming, 2/e
Functions, Informally The new program – def singFred(): happy() happy() print("Happy birthday, dear Fred...") happy() Gives us this output – >>> singFred() Happy birthday to you! Happy birthday to you! Happy birthday, dear Fred... Happy birthday to you! Python Programming, 2/e
Functions, Informally Creating this function saved us a lot of typing! What if it’s Lucy’s birthday? We could write a new singLucy function! def singLucy(): happy() happy() print("Happy birthday, dear Lucy...") happy() Python Programming, 2/e
Functions, Informally We could write a main program to sing to both Lucy and Fred def main(): singFred() print() singLucy() This gives us this new output >>> main() Happy birthday to you! Happy birthday to you! Happy birthday, dear Fred.. Happy birthday to you! Happy birthday to you! Happy birthday to you! Happy birthday, dear Lucy... Happy birthday to you! Python Programming, 2/e
Functions, Informally This is working great! But… there’s still a lot of code duplication. The only difference between singFred and singLucy is the name in the third print statement. These two routines could be collapsed together by using a parameter. Python Programming, 2/e
Functions, Informally The generic function sing def sing(person): happy() happy() print("Happy birthday, dear", person + ".“) happy() This function uses a parameter named person. A paramater is a variable that is initialized when the function is called. Python Programming, 2/e
Functions, Informally Our new output – >>> sing("Fred") Happy birthday to you! Happy birthday to you! Happy birthday, dear Fred. Happy birthday to you! We can put together a new main program! Python Programming, 2/e
Functions, Informally Our new main program: def main(): sing("Fred") print() sing("Lucy") Gives us this output: >>> main() Happy birthday to you! Happy birthday to you! Happy birthday, dear Fred. Happy birthday to you! Happy birthday to you! Happy birthday to you! Happy birthday, dear Lucy. Happy birthday to you! Python Programming, 2/e
Future Value with a Function In the future value graphing program, we see similar code twice: # Draw bar for initial principal bar = Rectangle(Point(0, 0), Point(1, principal)) bar.setFill("green") bar.setWidth(2) bar.draw(win) bar = Rectangle(Point(year, 0), Point(year+1, principal)) bar.setFill("green") bar.setWidth(2) bar.draw(win) Python Programming, 2/e
Future Value with a Function To properly draw the bars, we need three pieces of information. The year the bar is for How tall the bar should be The window the bar will be drawn in These three values can be supplied as parameters to the function. Python Programming, 2/e
Future Value with a Function The resulting function looks like this: def drawBar(window, year, height): # Draw a bar in window starting at year with given height bar = Rectangle(Point(year, 0), Point(year+1, height)) bar.setFill("green") bar.setWidth(2) bar.draw(window) To use this function, we supply the three values. If win is a Graphwin, we can draw a bar for year 0 and principal of $2000 using this call: drawBar(win, 0, 2000) Python Programming, 2/e
Functions and Parameters: The Details It makes sense to include the year and the principal in the drawBar function, but why send the window variable? The scope of a variable refers to the places in a program a given variable can be referenced. Python Programming, 2/e
Functions and Parameters: The Details Each function is its own little subprogram. The variables used inside of a function are local to that function, even if they happen to have the same name as variables that appear inside of another function. The only way for a function to see a variable from another function is for that variable to be passed as a parameter. Python Programming, 2/e
Functions and Parameters: The Details Since the GraphWin in the variable win is created inside of main, it is not directly accessible in drawBar. The window parameter in drawBar gets assigned the value of win from main when drawBar is called. Python Programming, 2/e
Functions and Parameters: The Details A function definition looks like this: def <name>(<formal-parameters>): <body> The name of the function must be an identifier Formal-parameters is a possibly empty list of variable names Python Programming, 2/e
Functions and Parameters: The Details Formal parameters, like all variables used in the function, are only accessible in the body of the function. Variables with identical names elsewhere in the program are distinct from the formal parameters and variables inside of the function body. Python Programming, 2/e
Functions and Parameters: The Details A function is called by using its name followed by a list of actual parameters or arguments. <name>(<actual-parameters>) When Python comes to a function call, it initiates a four-step process. Python Programming, 2/e
Functions and Parameters: The Details The calling program suspends execution at the point of the call. The formal parameters of the function get assigned the values supplied by the actual parameters in the call. The body of the function is executed. Control returns to the point just after where the function was called. Python Programming, 2/e
Functions and Parameters: The Details Let’s trace through the following code: sing("Fred") print() sing("Lucy") When Python gets to sing("Fred"), execution of main is temporarily suspended. Python looks up the definition of sing and sees that it has one formal parameter, person. Python Programming, 2/e
Functions and Parameters: The Detail The formal parameter is assigned the value of the actual parameter. It’s as if the following statement had been executed: person = "Fred" Python Programming, 2/e
Functions and Parameters: The Details Note that the variable person has just been initialized. Python Programming, 2/e
Functions and Parameters: The Details At this point, Python begins executing the body of sing. The first statement is another function call, to happy. What happens next? Python suspends the execution of sing and transfers control to happy. happy consists of a single print, which is executed and control returns to where it left off in sing. Python Programming, 2/e
Functions and Parameters: The Details Execution continues in this way with two more trips to happy. When Python gets to the end of sing, control returns to main and continues immediately following the function call. Python Programming, 2/e
Functions and Parameters: The Details Notice that the person variable in sing has disappeared! The memory occupied by local function variables is reclaimed when the function exits. Local variables do not retain any values from one function execution to the next. Python Programming, 2/e
Functions and Parameters: The Details The next statement is the bare print, which produces a blank line. Python encounters another call to sing, and control transfers to the sing function, with the formal parameter “Lucy”. Python Programming, 2/e
Functions and Parameters: The Details The body of sing is executed for Lucy with its three side trips to happy and control returns to main. Python Programming, 2/e
Functions and Parameters: The Details Python Programming, 2/e
Functions and Paramters: The Details One thing not addressed in this example was multiple parameters. In this case the formal and actual parameters are matched up based on position, e.g. the first actual parameter is assigned to the first formal parameter, the second actual parameter is assigned to the second formal parameter, etc. Python Programming, 2/e
Functions and Parameters: The Details As an example, consider the call to drawBar: drawBar(win, 0, principal) When control is passed to drawBar, these parameters are matched up to the formal parameters in the function heading: def drawBar(window, year, height): Python Programming, 2/e
Functions and Parameters: The Details The net effect is as if the function body had been prefaced with three assignment statements: window = win year = 0 height = principal Python Programming, 2/e
Getting Results from a Function Passing parameters provides a mechanism for initializing the variables in a function. Parameters act as inputs to a function. We can call a function many times and get different results by changing its parameters. Python Programming, 2/e
Functions That Return Values We’ve already seen numerous examples of functions that return values to the caller. discRt = math.sqrt(b*b – 4*a*c) The value b*b – 4*a*c is the actual parameter of math.sqrt. We say sqrt returns the square root of its argument. Python Programming, 2/e
Functions That Return Values This function returns the square of a number: def square(x): return x*x When Python encounters return, it exits the function and returns control to the point where the function was called. In addition, the value(s) provided in the return statement are sent back to the caller as an expression result. Python Programming, 2/e
Functions That Return Values >>> square(3) 9 >>> print(square(4)) 16 >>> x = 5 >>> y = square(x) >>> print(y) 25 >>> print(square(x) + square(3)) 34 Python Programming, 2/e
Functions That Return Values We can use the square function to write a routine to calculate the distance between (x1,y1) and (x2,y2). def distance(p1, p2): dist = math.sqrt(square(p2.getX() - p1.getX()) + square(p2.getY() - p1.getY())) return dist Python Programming, 2/e
Functions That Return Values Sometimes a function needs to return more than one value. To do this, simply list more than one expression in the return statement. def sumDiff(x, y): sum = x + y diff = x – y return sum, diff Python Programming, 2/e
Functions That Return Values When calling this function, use simultaneous assignment. num1, num2 = eval(input("Enter two numbers (num1, num2) ")) s, d = sumDiff(num1, num2) print("The sum is", s, "and the difference is", d) As before, the values are assigned based on position, so s gets the first value returned (the sum), and d gets the second (the difference). Python Programming, 2/e
Functions That Return Values One “gotcha” – all Python functions return a value, whether they contain a return statement or not. Functions without a return hand back a special object, denoted None. A common problem is writing a value-returning function and omitting the return! Python Programming, 2/e
Functions That Return Values If your value-returning functions produce strange messages, check to make sure you remembered to include the return! Python Programming, 2/e
Functions that Modify Parameters Return values are the main way to send information from a function back to the caller. Sometimes, we can communicate back to the caller by making changes to the function parameters. Understanding when and how this is possible requires the mastery of some subtle details about how assignment works and the relationship between actual and formal parameters. Python Programming, 2/e
Functions that Modify Parameters Suppose you are writing a program that manages bank accounts. One function we would need to do is to accumulate interest on the account. Let’s look at a first-cut at the function. def addInterest(balance, rate): newBalance = balance * (1 + rate) balance = newBalance Python Programming, 2/e
Functions that Modify Parameters The intent is to set the balance of the account to a new value that includes the interest amount. Let’s write a main program to test this: def test(): amount = 1000 rate = 0.05 addInterest(amount, rate) print(amount) Python Programming, 2/e
Functions that Modify Parameters We hope that that the 5% will be added to the amount, returning 1050. >>> test() 1000 What went wrong? Nothing! Python Programming, 2/e
Functions that Modify Parameters The first two lines of the test function create two local variables called amount and rate which are given the initial values of 1000 and 0.05, respectively. def addInterest(balance, rate): newBalance = balance * (1 + rate) balance = newBalance def test(): amount = 1000 rate = 0.05 addInterest(amount, rate) print(amount) Python Programming, 2/e
Functions that Modify Parameters Control then transfers to the addInterest function. The formal parameters balance and rate are assigned the values of the actual parameters amount and rate. Even though rate appears in both, they are separate variables (because of scope rules). def addInterest(balance, rate): newBalance = balance * (1 + rate) balance = newBalance def test(): amount = 1000 rate = 0.05 addInterest(amount, rate) print(amount) Python Programming, 2/e
Functions that Modify Parameters The assignment of the parameters causes the variables balance and rate in addInterest to refer to the values of the actual parameters! def addInterest(balance, rate): newBalance = balance*(1 + rate) balance = newBalance def test(): amount = 1000 rate = 0.05 addInterest(amount, rate) print(amount) Python Programming, 2/e
Functions that Modify Parameters Python Programming, 2/e
Functions that Modify Parameters Executing the first line of addInterest creates a new variable, newBalance. balance is then assigned the value of newBalance. def addInterest(balance, rate): newBalance = balance * (1 + rate) balance = newBalance def test(): amount = 1000 rate = 0.05 addInterest(amount, rate) print(amount) Python Programming, 2/e
Functions that Modify Parameters balance now refers to the same value as newBalance, but this had no effect on amount in the test function. def addInterest(balance, rate): newBalance = balance * (1 + rate) balance = newBalance def test(): amount = 1000 rate = 0.05 addInterest(amount, rate) print (amount) Python Programming, 2/e
Functions that Modify Parameters Python Programming, 2/e
Functions that Modify Parameters Execution of addInterest has completed and control returns to test. The local variables, including the parameters, in addInterest go away, but amount and rate in the test function still refer to their initial values! def addInterest(balance, rate): newBalance = balance * (1 + rate) balance = newBalance def test(): amount = 1000 rate = 0.05 addInterest(amount, rate) print(amount) Python Programming, 2/e
Functions that Modify Parameters To summarize: the formal parameters of a function only receive the values of the actual parameters. The function does not have access to the variable that holds the actual parameter. Python is said to pass all parameters by value. Python Programming, 2/e
Functions that Modify Parameters Some programming languages (C++, Ada, and many more) do allow variables themselves to be sent as parameters to a function. This mechanism is said to pass parameters by reference. When a new value is assigned to the formal parameter, the value of the variable in the calling program actually changes. Python Programming, 2/e
Functions that Modify Parameters Since Python doesn’t have this capability, one alternative would be to change the addInterest function so that it returns the newBalance. Python Programming, 2/e
Functions that Modify Parameters def addInterest(balance, rate): newBalance = balance * (1 + rate) return newBalance def test(): amount = 1000 rate = 0.05 amount = addInterest(amount, rate) print(amount) test() Python Programming, 2/e
Functions that Modify Parameters Instead of looking at a single account, say we are writing a program for a bank that deals with many accounts. We could store the account balances in a list, then add the accrued interest to each of the balances in the list. We could update the first balance in the list with code like: balances[0] = balances[0] * (1 + rate) Python Programming, 2/e
Functions that Modify Parameters This code says, “multiply the value in the 0th position of the list by (1 + rate) and store the result back into the 0th position of the list.” A more general way to do this would be with a loop that goes through positions 0, 1, …, length – 1. Python Programming, 2/e
Functions that Modify Parameters # addinterest3.py # Illustrates modification of a mutable parameter (a list). def addInterest(balances, rate): for i in range(len(balances)): balances[i] = balances[i] * (1+rate) def test(): amounts = [1000, 2200, 800, 360] rate = 0.05 addInterest(amounts, 0.05) print(amounts) test() Python Programming, 2/e
Functions that Modify Parameters Remember, our original code had these values: [1000, 2200, 800, 360] The program returns: [1050.0, 2310.0, 840.0, 378.0] What happened? Python passes parameters by value, but it looks like amounts has been changed! Python Programming, 2/e
Functions that Modify Parameters The first two lines of test create the variables amounts and rate. The value of the variable amounts is a list object that contains four int values. def addInterest(balances, rate): for i in range(len(balances)): balances[i] = balances[i] * (1+rate) def test(): amounts = [1000, 2200, 800, 360] rate = 0.05 addInterest(amounts, 0.05) print(amounts) Python Programming, 2/e
Functions that Modify Parameters Python Programming, 2/e
Functions that Modify Parameters Next, addInterest executes. The loop goes through each index in the range 0, 1, …, length –1 and updates that value in balances. def addInterest(balances, rate): for i in range(len(balances)): balances[i] = balances[i] * (1+rate) def test(): amounts = [1000, 2200, 800, 360] rate = 0.05 addInterest(amounts, 0.05) print(amounts) Python Programming, 2/e
Functions that Modify Parameters Python Programming, 2/e
Functions that Modify Parameters In the diagram the old values are left hanging around to emphasize that the numbers in the boxes have not changed, but the new values were created and assigned into the list. The old values will be destroyed during garbage collection. def addInterest(balances, rate): for i in range(len(balances)): balances[i] = balances[i] * (1+rate) def test(): amounts = [1000, 2200, 800, 360] rate = 0.05 addInterest(amounts, 0.05) print amounts Python Programming, 2/e
Functions that Modify Parameters When addInterest terminates, the list stored in amounts now contains the new values. The variable amounts wasn’t changed (it’s still a list), but the state of that list has changed, and this change is visible to the calling program. Python Programming, 2/e
Functions that Modify Parameters Parameters are always passed by value. However, if the value of the variable is a mutable object (like a list of graphics object), then changes to the state of the object will be visible to the calling program. This situation is another example of the aliasing issue discussed in Chapter 4! Python Programming, 2/e
Functions and Program Structure So far, functions have been used as a mechanism for reducing code duplication. Another reason to use functions is to make your programs more modular. As the algorithms you design get increasingly complex, it gets more and more difficult to make sense out of the programs. Python Programming, 2/e
Functions and Program Structure One way to deal with this complexity is to break an algorithm down into smaller subprograms, each of which makes sense on its own. This topic will be discussed in more detail in Chapter 9. Python Programming, 2/e
Functions and Program Structure def main(): # Introduction print("This program plots the growth of a 10 year investment.") # Get principal and interest rate principal = eval(input("Enter the initial principal: ")) apr = eval(input("Enter the annualized interest rate: ")) # Create a graphics window with labels on left edge win = GraphWin("Investment Growth Chart", 320, 240) win.setBackground("white") win.setCoords(-1.75,-200, 11.5, 10400) Text(Point(-1, 0), ' 0.0K').draw(win) Text(Point(-1, 2500), ' 2.5K').draw(win) Text(Point(-1, 5000), ' 5.0K').draw(win) Text(Point(-1, 7500), ' 7.5k').draw(win) Text(Point(-1, 10000), '10.0K').draw(win) # Draw bar for initial principal drawBar(win, 0, principal) # Draw a bar for each subsequent year for year in range(1, 11): principal = principal * (1 + apr) drawBar(win, year, principal) input("Press <Enter> to quit.") win.close() Python Programming, 2/e
Functions and Program Structure We can make this program more readable by moving the middle eight lines that create the window where the chart will be drawn into a value returning function. Python Programming, 2/e
Functions and Program Structure def createLabeledWindow(): window = GraphWin("Investment Growth Chart", 320, 240) window.setBackground("white") window.setCoords(-1.75,-200, 11.5, 10400) Text(Point(-1, 0), ' 0.0K').draw(window) Text(Point(-1, 2500), ' 2.5K').draw(window) Text(Point(-1, 5000), ' 5.0K').draw(window) Text(Point(-1, 7500), ' 7.5k').draw(window) Text(Point(-1, 10000), '10.0K').draw(window) return window def main(): print("This program plots the growth of a 10 year investment.") principal = eval(input("Enter the initial principal: ")) apr = eval(input("Enter the annualized interest rate: ")) win = createLabeledWindow() drawBar(win, 0, principal) for year in range(1, 11): principal = principal * (1 + apr) drawBar(win, year, principal) input("Press <Enter> to quit.") win.close() Python Programming, 2/e
Python Programming: An Introduction to Computer Science Chapter 7 Decision Structures Python Programming, 2/e
Objectives To understand the programming pattern simple decision and its implementation using a Python if statement. To understand the programming pattern two-way decision and its implementation using a Python if-else statement. Python Programming, 2/e
Objectives (cont.) To understand the programming pattern multi-way decision and its implementation using a Python if-elif-else statement. To understand the idea of exception handling and be able to write simple exception handling code that catches standard Python run-time errors. Python Programming, 2/e
Objectives (cont.) To understand the concept of Boolean expressions and the bool data type. To be able to read, write, and implement algorithms that employ decision structures, including those that employ sequences of decisions and nested decision structures. Python Programming, 2/e
Simple Decisions So far, we’ve viewed programs as sequences of instructions that are followed one after the other. While this is a fundamental programming concept, it is not sufficient in itself to solve every problem. We need to be able to alter the sequential flow of a program to suit a particular situation. Python Programming, 2/e Python Programming, 1/e
Simple Decisions Control structures allow us to alter this sequential program flow. In this chapter, we’ll learn about decision structures, which are statements that allow a program to execute different sequences of instructions for different cases, allowing the program to “choose” an appropriate course of action. Python Programming, 2/e
Example: Temperature Warnings Let’s return to our Celsius to Fahrenheit temperature conversion program from Chapter 2. # convert.py # A program to convert Celsius temps to Fahrenheit # by: Susan Computewell def main(): celsius = eval(input("What is the Celsius temperature? ")) fahrenheit = 9/5 * celsius + 32 print("The temperature is", fahrenheit, "degrees Fahrenheit.") main() Python Programming, 2/e
Example: Temperature Warnings Let’s say we want to modify that program to print a warning when the weather is extreme. Any temperature over 90 degrees Fahrenheit and lower than 30 degrees Fahrenheit will cause a hot and cold weather warning, respectively. Python Programming, 2/e
Example: Temperature Warnings Input the temperature in degrees Celsius (call it celsius) Calculate fahrenheit as 9/5 celsius + 32 Output fahrenheit If fahrenheit > 90 print a heat warning If fahrenheit > 30 print a cold warning Python Programming, 2/e
Example: Temperature Warnings This new algorithm has two decisions at the end. The indentation indicates that a step should be performed only if the condition listed in the previous line is true. Python Programming, 2/e
Example: Temperature Warnings Python Programming, 2/e
Example: Temperature Warnings # convert2.py # A program to convert Celsius temps to Fahrenheit. # This version issues heat and cold warnings. def main(): celsius = eval(input("What is the Celsius temperature? ")) fahrenheit = 9 / 5 * celsius + 32 print("The temperature is", fahrenheit, "degrees fahrenheit.") if fahrenheit >= 90: print("It's really hot out there, be careful!") if fahrenheit <= 30: print("Brrrrr. Be sure to dress warmly") main() Python Programming, 2/e
Example: Temperature Warnings The Python if statement is used to implement the decision. if <condition>: <body> The body is a sequence of one or more statements indented under the if heading. Python Programming, 2/e
Example: Temperature Warnings The semantics of the if should be clear. First, the condition in the heading is evaluated. If the condition is true, the sequence of statements in the body is executed, and then control passes to the next statement in the program. If the condition is false, the statements in the body are skipped, and control passes to the next statement in the program. Python Programming, 2/e
Example: Temperature Warnings Python Programming, 2/e
Example: Temperature Warnings The body of the if either executes or not depending on the condition. In any case, control then passes to the next statement after the if. This is a one-way or simple decision. Python Programming, 2/e
Forming Simple Conditions What does a condition look like? At this point, let’s use simple comparisons. <expr> <relop> <expr> <relop> is short for relational operator Python Programming, 2/e
Forming Simple Conditions Python Mathematics Meaning < Less than <= ≤ Less than or equal to == = Equal to >= ≥ Greater than or equal to > Greater than != ≠ Not equal to Python Programming, 2/e
Forming Simple Conditions Notice the use of == for equality. Since Python uses = to indicate assignment, a different symbol is required for the concept of equality. A common mistake is using = in conditions! Python Programming, 2/e
Forming Simple Conditions Conditions may compare either numbers or strings. When comparing strings, the ordering is lexigraphic, meaning that the strings are sorted based on the underlying Unicode. Because of this, all upper-case letters come before lower-case letters. (“Bbbb” comes before “aaaa”) Python Programming, 2/e
Forming Simple Conditions Conditions are based on Boolean expressions, named for the English mathematician George Boole. When a Boolean expression is evaluated, it produces either a value of true (meaning the condition holds), or it produces false (it does not hold). Some computer languages use 1 and 0 to represent “true” and “false”. Python Programming, 2/e
Forming Simple Conditions Boolean conditions are of type bool and the Boolean values of true and false are represented by the literals True and False. >>> 3 < 4 True >>> 3 * 4 < 3 + 4 False >>> "hello" == "hello" >>> "Hello" < "hello" Python Programming, 2/e
Example: Conditional Program Execution There are several ways of running Python programs. Some modules are designed to be run directly. These are referred to as programs or scripts. Others are made to be imported and used by other programs. These are referred to as libraries. Sometimes we want to create a hybrid that can be used both as a stand-alone program and as a library. Python Programming, 2/e
Example: Conditional Program Execution When we want to start a program once it’s loaded, we include the line main() at the bottom of the code. Since Python evaluates the lines of the program during the import process, our current programs also run when they are imported into an interactive Python session or into another Python program. Python Programming, 2/e
Example: Conditional Program Execution Generally, when we import a module, we don’t want it to execute! In a program that can be either run stand-alone or loaded as a library, the call to main at the bottom should be made conditional, e.g. if <condition>: main() Python Programming, 2/e
Example: Conditional Program Execution Whenever a module is imported, Python creates a special variable in the module called __name__ to be the name of the imported module. Example: >>> import math >>> math.__name__ 'math' Python Programming, 2/e
Example: Conditional Program Execution When imported, the __name__ variable inside the math module is assigned the string ‘math’. When Python code is run directly and not imported, the value of __name__ is ‘__main__’. E.g.: >>> __name__ '__main__' Python Programming, 2/e
Example: Conditional Program Execution To recap: if a module is imported, the code in the module will see a variable called __name__ whose value is the name of the module. When a file is run directly, the code will see the value ‘__main__’. We can change the final lines of our programs to: if __name__ == '__main__': main() Virtually every Python module ends this way! Python Programming, 2/e
Two-Way Decisions Consider the quadratic program as we left it. # quadratic.py # A program that computes the real roots of a quadratic equation. # Note: This program crashes if the equation has no real roots. import math def main(): print("This program finds the real solutions to a quadratic") a, b, c = eval(input("\nPlease enter the coefficients (a, b, c): ")) discRoot = math.sqrt(b * b - 4 * a * c) root1 = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a) print("\nThe solutions are:", root1, root2) main() Python Programming, 2/e
Two-Way Decisions As per the comment, when b2-4ac < 0, the program crashes. This program finds the real solutions to a quadratic Please enter the coefficients (a, b, c): 1,1,2 Traceback (most recent call last): File "C:\Documents and Settings\Terry\My Documents\Teaching\W04\CS 120\Textbook\code\chapter3\quadratic.py", line 21, in -toplevel- main() File "C:\Documents and Settings\Terry\My Documents\Teaching\W04\CS 120\Textbook\code\chapter3\quadratic.py", line 14, in main discRoot = math.sqrt(b * b - 4 * a * c) ValueError: math domain error Python Programming, 2/e
Two-Way Decisions We can check for this situation. Here’s our first attempt. # quadratic2.py # A program that computes the real roots of a quadratic equation. # Bad version using a simple if to avoid program crash import math def main(): print("This program finds the real solutions to a quadratic\n") a, b, c = eval(input("Please enter the coefficients (a, b, c): ")) discrim = b * b - 4 * a * c if discrim >= 0: discRoot = math.sqrt(discrim) root1 = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a) print("\nThe solutions are:", root1, root2) Python Programming, 2/e
Two-Way Decisions We first calculate the discriminant (b2-4ac) and then check to make sure it’s nonnegative. If it is, the program proceeds and we calculate the roots. Look carefully at the program. What’s wrong with it? Hint: What happens when there are no real roots? Python Programming, 2/e
Two-Way Decisions This program finds the real solutions to a quadratic Please enter the coefficients (a, b, c): 1,1,1 >>> This is almost worse than the version that crashes, because we don’t know what went wrong! Python Programming, 2/e
Two-Way Decisions We could add another if to the end: if discrim < 0: print("The equation has no real roots!" ) This works, but feels wrong. We have two decisions, with mutually exclusive outcomes (if discrim >= 0 then discrim < 0 must be false, and vice versa). Python Programming, 2/e
Two-Way Decisions Python Programming, 2/e
Two-Way Decisions In Python, a two-way decision can be implemented by attaching an else clause onto an if clause. This is called an if-else statement: if <condition>: <statements> else: <statements> Python Programming, 2/e
Two-Way Decisions When Python first encounters this structure, it first evaluates the condition. If the condition is true, the statements under the if are executed. If the condition is false, the statements under the else are executed. In either case, the statements following the if-else are executed after either set of statements are executed. Python Programming, 2/e
Two-Way Decisions Python Programming, 2/e # quadratic3.py # A program that computes the real roots of a quadratic equation. # Illustrates use of a two-way decision import math def main(): print "This program finds the real solutions to a quadratic\n" a, b, c = eval(input("Please enter the coefficients (a, b, c): ")) discrim = b * b - 4 * a * c if discrim < 0: print("\nThe equation has no real roots!") else: discRoot = math.sqrt(b * b - 4 * a * c) root1 = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a) print ("\nThe solutions are:", root1, root2 ) main() Python Programming, 2/e
Two-Way Decisions >>> This program finds the real solutions to a quadratic Please enter the coefficients (a, b, c): 1,1,2 The equation has no real roots! Please enter the coefficients (a, b, c): 2, 5, 2 The solutions are: -0.5 -2.0 Python Programming, 2/e
Multi-Way Decisions The newest program is great, but it still has some quirks! This program finds the real solutions to a quadratic Please enter the coefficients (a, b, c): 1,2,1 The solutions are: -1.0 -1.0 Python Programming, 2/e
Multi-Way Decisions While correct, this method might be confusing for some people. It looks like it has mistakenly printed the same number twice! Double roots occur when the discriminant is exactly 0, and then the roots are –b/2a. It looks like we need a three-way decision! Python Programming, 2/e
Multi-Way Decisions Check the value of discrim when < 0: handle the case of no roots when = 0: handle the case of a double root when > 0: handle the case of two distinct roots We can do this with two if-else statements, one inside the other. Putting one compound statement inside of another is called nesting. Python Programming, 2/e
Multi-Way Decisions if discrim < 0: print("Equation has no real roots") else: if discrim == 0: root = -b / (2 * a) print("There is a double root at", root) # Do stuff for two roots Python Programming, 2/e
Multi-Way Decisions Python Programming, 2/e
Multi-Way Decisions Imagine if we needed to make a five-way decision using nesting. The if-else statements would be nested four levels deep! There is a construct in Python that achieves this, combining an else followed immediately by an if into a single elif. Python Programming, 2/e
Multi-Way Decisions if <condition1>: <case1 statements> elif <condition2>: <case2 statements> elif <condition3>: <case3 statements> … else: <default statements> Python Programming, 2/e
Multi-Way Decisions This form sets of any number of mutually exclusive code blocks. Python evaluates each condition in turn looking for the first one that is true. If a true condition is found, the statements indented under that condition are executed, and control passes to the next statement after the entire if-elif-else. If none are true, the statements under else are performed. Python Programming, 2/e
Multi-Way Decisions The else is optional. If there is no else, it’s possible no indented block would be executed. Python Programming, 2/e
Multi-Way Decisions Python Programming, 2/e # quadratic4.py # Illustrates use of a multi-way decision import math def main(): print("This program finds the real solutions to a quadratic\n") a, b, c = eval(input("Please enter the coefficients (a, b, c): ")) discrim = b * b - 4 * a * c if discrim < 0: print("\nThe equation has no real roots!") elif discrim == 0: root = -b / (2 * a) print("\nThere is a double root at", root) else: discRoot = math.sqrt(b * b - 4 * a * c) root1 = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a) print("\nThe solutions are:", root1, root2 ) Python Programming, 2/e
Exception Handling In the quadratic program we used decision structures to avoid taking the square root of a negative number, thus avoiding a run-time error. This is true for many programs: decision structures are used to protect against rare but possible errors. Python Programming, 2/e
Exception Handling In the quadratic example, we checked the data before calling sqrt. Sometimes functions will check for errors and return a special value to indicate the operation was unsuccessful. E.g., a different square root operation might return a –1 to indicate an error (since square roots are never negative, we know this value will be unique). Python Programming, 2/e
Exception Handling discRt = otherSqrt(b*b - 4*a*c) if discRt < 0: print("No real roots.“) else: ... Sometimes programs get so many checks for special cases that the algorithm becomes hard to follow. Programming language designers have come up with a mechanism to handle exception handling to solve this design problem. Python Programming, 2/e
Exception Handling The programmer can write code that catches and deals with errors that arise while the program is running, i.e., “Do these steps, and if any problem crops up, handle it this way.” This approach obviates the need to do explicit checking at each step in the algorithm. Python Programming, 2/e
Exception Handling # quadratic5.py # A program that computes the real roots of a quadratic equation. # Illustrates exception handling to avoid crash on bad inputs import math def main(): print("This program finds the real solutions to a quadratic\n") try: a, b, c = eval(input("Please enter the coefficients (a, b, c): ")) discRoot = math.sqrt(b * b - 4 * a * c) root1 = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a) print("\nThe solutions are:", root1, root2) except ValueError: print("\nNo real roots") Python Programming, 2/e
Exception Handling The try statement has the following form: try: <body> except <ErrorType>: <handler> When Python encounters a try statement, it attempts to execute the statements inside the body. If there is no error, control passes to the next statement after the try…except. Python Programming, 2/e
Exception Handling If an error occurs while executing the body, Python looks for an except clause with a matching error type. If one is found, the handler code is executed. The original program generated this error with a negative discriminant: Traceback (most recent call last): File "C:\Documents and Settings\Terry\My Documents\Teaching\W04\CS120\Textbook\code\chapter3\quadratic.py", line 21, in -toplevel- main() File "C:\Documents and Settings\Terry\My Documents\Teaching\W04\CS 120\Textbook\code\chapter3\quadratic.py", line 14, in main discRoot = math.sqrt(b * b - 4 * a * c) ValueError: math domain error Python Programming, 2/e
Exception Handling The last line, “ValueError: math domain error”, indicates the specific type of error. Here’s the new code in action: This program finds the real solutions to a quadratic Please enter the coefficients (a, b, c): 1, 1, 1 No real roots Instead of crashing, the exception handler prints a message indicating that there are no real roots. Python Programming, 2/e
Exception Handling The try…except can be used to catch any kind of error and provide for a graceful exit. In the case of the quadratic program, other possible errors include not entering the right number of parameters (“unpack tuple of wrong size”), entering an identifier instead of a number (NameError), entering an invalid Python expression (TypeError). A single try statement can have multiple except clauses. Python Programming, 2/e
Exception Handling Python Programming, 2/e # quadratic6.py import math def main(): print("This program finds the real solutions to a quadratic\n") try: a, b, c = eval(input("Please enter the coefficients (a, b, c): ")) discRoot = math.sqrt(b * b - 4 * a * c) root1 = (-b + discRoot) / (2 * a) root2 = (-b - discRoot) / (2 * a) print("\nThe solutions are:", root1, root2 ) except ValueError as excObj: if str(excObj) == "math domain error": print("No Real Roots") else: print("You didn't give me the right number of coefficients.") except NameError: print("\nYou didn't enter three numbers.") except TypeError: print("\nYour inputs were not all numbers.") except SyntaxError: print("\nYour input was not in the correct form. Missing comma?") except: print("\nSomething went wrong, sorry!") main() Python Programming, 2/e
Exception Handling The multiple excepts act like elifs. If an error occurs, Python will try each except looking for one that matches the type of error. The bare except at the bottom acts like an else and catches any errors without a specific match. If there was no bare except at the end and none of the except clauses match, the program would still crash and report an error. Python Programming, 2/e
Exception Handling Exceptions themselves are a type of object. If you follow the error type with an identifier in an except clause, Python will assign that identifier the actual exception object. Python Programming, 2/e
Study in Design: Max of Three Now that we have decision structures, we can solve more complicated programming problems. The negative is that writing these programs becomes harder! Suppose we need an algorithm to find the largest of three numbers. Python Programming, 2/e
Study in Design: Max of Three def main(): x1, x2, x3 = eval(input("Please enter three values: ")) # missing code sets max to the value of the largest print("The largest value is", max) Python Programming, 2/e
Strategy 1: Compare Each to All This looks like a three-way decision, where we need to execute one of the following: max = x1 max = x2 max = x3 All we need to do now is preface each one of these with the right condition! Python Programming, 2/e
Strategy 1: Compare Each to All Let’s look at the case where x1 is the largest. if x1 >= x2 >= x3: max = x1 Is this syntactically correct? Many languages would not allow this compound condition Python does allow it, though. It’s equivalent to x1 ≥ x2 ≥ x3. Python Programming, 2/e
Strategy 1: Compare Each to All Whenever you write a decision, there are two crucial questions: When the condition is true, is executing the body of the decision the right action to take? x1 is at least as large as x2 and x3, so assigning max to x1 is OK. Always pay attention to borderline values!! Python Programming, 2/e
Strategy 1: Compare Each to All Secondly, ask the converse of the first question, namely, are we certain that this condition is true in all cases where x1 is the max? Suppose the values are 5, 2, and 4. Clearly, x1 is the largest, but does x1 ≥ x2 ≥ x3 hold? We don’t really care about the relative ordering of x2 and x3, so we can make two separate tests: x1 >= x2 and x1 >= x3. Python Programming, 2/e
Strategy 1: Compare Each to All We can separate these conditions with and! if x1 >= x2 and x1 >= x3: max = x1 elif x2 >= x1 and x2 >= x3: max = x2 else: max = x3 We’re comparing each possible value against all the others to determine which one is largest. Python Programming, 2/e
Strategy 1: Compare Each to All What would happen if we were trying to find the max of five values? We would need four Boolean expressions, each consisting of four conditions anded together. Yuck! Python Programming, 2/e
Strategy 2: Decision Tree We can avoid the redundant tests of the previous algorithm using a decision tree approach. Suppose we start with x1 >= x2. This knocks either x1 or x2 out of contention to be the max. If the conidition is true, we need to see which is larger, x1 or x3. Python Programming, 2/e
Strategy 2: Decision Tree Python Programming, 2/e
Strategy 2: Decision Tree if x1 >= x2: if x1 >= x3: max = x1 else: max = x3 else: if x2 >= x3: max = x2 else max = x3 Python Programming, 2/e
Strategy 2: Decision Tree This approach makes exactly two comparisons, regardless of the ordering of the original three variables. However, this approach is more complicated than the first. To find the max of four values you’d need if-elses nested three levels deep with eight assignment statements. Python Programming, 2/e
Strategy 3: Sequential Processing How would you solve the problem? You could probably look at three numbers and just know which is the largest. But what if you were given a list of a hundred numbers? One strategy is to scan through the list looking for a big number. When one is found, mark it, and continue looking. If you find a larger value, mark it, erase the previous mark, and continue looking. Python Programming, 2/e
Strategy 3: Sequential Processing Python Programming, 2/e
Strategy 3: Sequential Processing This idea can easily be translated into Python. max = x1 if x2 > max: max = x2 if x3 > max: max = x3 Python Programming, 2/e
Strategy 3: Sequential Programming This process is repetitive and lends itself to using a loop. We prompt the user for a number, we compare it to our current max, if it is larger, we update the max value, repeat. Python Programming, 2/e
Strategy 3: Sequential Programming # maxn.py # Finds the maximum of a series of numbers def main(): n = eval(input("How many numbers are there? ")) # Set max to be the first value max = eval(input("Enter a number >> ")) # Now compare the n-1 successive values for i in range(n-1): x = eval(input("Enter a number >> ")) if x > max: max = x print("The largest value is", max) Python Programming, 2/e
Strategy 4: Use Python Python has a built-in function called max that returns the largest of its parameters. def main(): x1, x2, x3 = eval(input("Please enter three values: ")) print("The largest value is", max(x1, x2, x3)) Python Programming, 2/e
Some Lessons There’s usually more than one way to solve a problem. Don’t rush to code the first idea that pops out of your head. Think about the design and ask if there’s a better way to approach the problem. Your first task is to find a correct algorithm. After that, strive for clarity, simplicity, efficiency, scalability, and elegance. Python Programming, 2/e
Some Lessons Be the computer. One of the best ways to formulate an algorithm is to ask yourself how you would solve the problem. This straightforward approach is often simple, clear, and efficient enough. Python Programming, 2/e
Some Lessons Generality is good. Consideration of a more general problem can lead to a better solution for a special case. If the max of n program is just as easy to write as the max of three, write the more general program because it’s more likely to be useful in other situations. Python Programming, 2/e
Some Lessons Don’t reinvent the wheel. If the problem you’re trying to solve is one that lots of other people have encountered, find out if there’s already a solution for it! As you learn to program, designing programs from scratch is a great experience! Truly expert programmers know when to borrow. Python Programming, 2/e
Python Programming: An Introduction To Computer Science Chapter 8 Loop Structures and Booleans Python Programming, 2/e
Objectives To understand the concepts of definite and indefinite loops as they are realized in the Python for and while statements. To understand the programming patterns interactive loop and sentinel loop and their implementations using a Python while statement. Python Programming, 2/e
Objectives To understand the programming pattern end-of-file loop and ways of implementing such loops in Python. To be able to design and implement solutions to problems involving loop patterns including nested loop structures. Python Programming, 2/e
Objectives To understand the basic ideas of Boolean algebra and be able to analyze and write Boolean expressions involving Boolean operators. Python Programming, 2/e
For Loops: A Quick Review The for statement allows us to iterate through a sequence of values. for <var> in <sequence>: <body> The loop index variable var takes on each successive value in the sequence, and the statements in the body of the loop are executed once for each value. Python Programming, 2/e Python Programming, 1/e
For Loops: A Quick Review Suppose we want to write a program that can compute the average of a series of numbers entered by the user. To make the program general, it should work with any size set of numbers. We don’t need to keep track of each number entered, we only need know the running sum and how many numbers have been added. Python Programming, 2/e
For Loops: A Quick Review We’ve run into some of these things before! A series of numbers could be handled by some sort of loop. If there are n numbers, the loop should execute n times. We need a running sum. This will use an accumulator. Python Programming, 2/e
For Loops: A Quick Review Input the count of the numbers, n Initialize sum to 0 Loop n times Input a number, x Add x to sum Output average as sum/n Python Programming, 2/e
For Loops: A Quick Review # average1.py # A program to average a set of numbers # Illustrates counted loop with accumulator def main(): n = eval(input("How many numbers do you have? ")) sum = 0.0 for i in range(n): x = eval(input("Enter a number >> ")) sum = sum + x print("\nThe average of the numbers is", sum / n) Note that sum is initialized to 0.0 so that sum/n returns a float! Python Programming, 2/e
For Loops: A Quick Review How many numbers do you have? 5 Enter a number >> 32 Enter a number >> 45 Enter a number >> 34 Enter a number >> 76 The average of the numbers is 46.4 Python Programming, 2/e
Indefinite Loops That last program got the job done, but you need to know ahead of time how many numbers you’ll be dealing with. What we need is a way for the computer to take care of counting how many numbers there are. The for loop is a definite loop, meaning that the number of iterations is determined when the loop starts. Python Programming, 2/e
Indefinite Loops We can’t use a definite loop unless we know the number of iterations ahead of time. We can’t know how many iterations we need until all the numbers have been entered. We need another tool! The indefinite or conditional loop keeps iterating until certain conditions are met. Python Programming, 2/e
Indefinite Loops while <condition>: <body> condition is a Boolean expression, just like in if statements. The body is a sequence of one or more statements. Semantically, the body of the loop executes repeatedly as long as the condition remains true. When the condition is false, the loop terminates. Python Programming, 2/e
Indefinite Loops The condition is tested at the top of the loop. This is known as a pre-test loop. If the condition is initially false, the loop body will not execute at all. Python Programming, 2/e
Indefinite Loop Here’s an example of a while loop that counts from 0 to 10: i = 0 while i <= 10: print(i) i = i + 1 The code has the same output as this for loop: for i in range(11): print(i) Python Programming, 2/e
Indefinite Loop The while loop requires us to manage the loop variable i by initializing it to 0 before the loop and incrementing it at the bottom of the body. In the for loop this is handled automatically. Python Programming, 2/e
Indefinite Loop The while statement is simple, but yet powerful and dangerous – they are a common source of program errors. i = 0 while i <= 10: print(i) What happens with this code? Python Programming, 2/e
Indefinite Loop When Python gets to this loop, i is equal to 0, which is less than 10, so the body of the loop is executed, printing 0. Now control returns to the condition, and since i is still 0, the loop repeats, etc. This is an example of an infinite loop. Python Programming, 2/e
Indefinite Loop What should you do if you’re caught in an infinite loop? First, try pressing control-c If that doesn’t work, try control-alt-delete If that doesn’t work, push the reset button! Python Programming, 2/e
Interactive Loops One good use of the indefinite loop is to write interactive loops. Interactive loops allow a user to repeat certain portions of a program on demand. Remember how we said we needed a way for the computer to keep track of how many numbers had been entered? Let’s use another accumulator, called count. Python Programming, 2/e
Interactive Loops At each iteration of the loop, ask the user if there is more data to process. We need to preset it to “yes” to go through the loop the first time. set moredata to “yes” while moredata is “yes” get the next data item process the item ask user if there is moredata Python Programming, 2/e
Interactive Loops Combining the interactive loop pattern with accumulators for sum and count: initialize sum to 0.0 initialize count to 0 set moredata to “yes” while moredata is “yes” input a number, x add x to sum add 1 to count ask user if there is moredata output sum/count Python Programming, 2/e
Interactive Loops # average2.py # A program to average a set of numbers # Illustrates interactive loop with two accumulators def main(): moredata = "yes" sum = 0.0 count = 0 while moredata[0] == 'y': x = eval(input("Enter a number >> ")) sum = sum + x count = count + 1 moredata = input("Do you have more numbers (yes or no)? ") print("\nThe average of the numbers is", sum / count) Using string indexing (moredata[0]) allows us to accept “y”, “yes”, “yeah” to continue the loop Python Programming, 2/e
Interactive Loops Enter a number >> 32 Do you have more numbers (yes or no)? y Enter a number >> 45 Do you have more numbers (yes or no)? yes Enter a number >> 34 Do you have more numbers (yes or no)? yup Enter a number >> 76 Do you have more numbers (yes or no)? nah The average of the numbers is 46.4 Python Programming, 2/e
Sentinel Loops A sentinel loop continues to process data until reaching a special value that signals the end. This special value is called the sentinel. The sentinel must be distinguishable from the data since it is not processed as part of the data. Python Programming, 2/e
Sentinel Loops get the first data item while item is not the sentinel process the item get the next data item The first item is retrieved before the loop starts. This is sometimes called the priming read, since it gets the process started. If the first item is the sentinel, the loop terminates and no data is processed. Otherwise, the item is processed and the next one is read. Python Programming, 2/e
Sentinel Loops In our averaging example, assume we are averaging test scores. We can assume that there will be no score below 0, so a negative number will be the sentinel. Python Programming, 2/e
Sentinel Loops # average3.py # A program to average a set of numbers # Illustrates sentinel loop using negative input as sentinel def main(): sum = 0.0 count = 0 x = eval(input("Enter a number (negative to quit) >> ")) while x >= 0: sum = sum + x count = count + 1 print("\nThe average of the numbers is", sum / count) Python Programming, 2/e
Sentinel Loops Enter a number (negative to quit) >> 32 The average of the numbers is 46.4 Python Programming, 2/e
Sentinel Loops This version provides the ease of use of the interactive loop without the hassle of typing ‘y’ all the time. There’s still a shortcoming – using this method we can’t average a set of positive and negative numbers. If we do this, our sentinel can no longer be a number. Python Programming, 2/e
Sentinel Loops We could input all the information as strings. Valid input would be converted into numeric form. Use a character-based sentinel. We could use the empty string (“”)! Python Programming, 2/e
Sentinel Loops initialize sum to 0.0 initialize count to 0 input data item as a string, xStr while xStr is not empty convert xStr to a number, x add x to sum add 1 to count input next data item as a string, xStr Output sum / count Python Programming, 2/e
Sentinel Loops # average4.py # A program to average a set of numbers # Illustrates sentinel loop using empty string as sentinel def main(): sum = 0.0 count = 0 xStr = input("Enter a number (<Enter> to quit) >> ") while xStr != "": x = eval(xStr) sum = sum + x count = count + 1 print("\nThe average of the numbers is", sum / count) Python Programming, 2/e
Sentinel Loops Enter a number (<Enter> to quit) >> 34 The average of the numbers is 3.38333333333 Python Programming, 2/e
File Loops The biggest disadvantage of our program at this point is that they are interactive. What happens if you make a typo on number 43 out of 50? A better solution for large data sets is to read the data from a file. Python Programming, 2/e
File Loops # average5.py # Computes the average of numbers listed in a file. def main(): fileName = input("What file are the numbers in? ") infile = open(fileName,'r') sum = 0.0 count = 0 for line in infile.readlines(): sum = sum + eval(line) count = count + 1 print("\nThe average of the numbers is", sum / count) Python Programming, 2/e
File Loops Many languages don’t have a mechanism for looping through a file like this. Rather, they use a sentinel! We could use readline in a loop to get the next line of the file. At the end of the file, readline returns an empty string, “” Python Programming, 2/e
File Loops line = infile.readline() while line != "" #process line line = infile.readline() Does this code correctly handle the case where there’s a blank line in the file? Yes. An empty line actually ends with the newline character, and readline includes the newline. “\n” != “” Python Programming, 2/e
File Loops # average6.py # Computes the average of numbers listed in a file. def main(): fileName = input("What file are the numbers in? ") infile = open(fileName,'r') sum = 0.0 count = 0 line = infile.readline() while line != "": sum = sum + eval(line) count = count + 1 print("\nThe average of the numbers is", sum / count) Python Programming, 2/e
Nested Loops In the last chapter we saw how we could nest if statements. We can also nest loops. Suppose we change our specification to allow any number of numbers on a line in the file (separated by commas), rather than one per line. Python Programming, 2/e
Nested Loops At the top level, we will use a file-processing loop that computes a running sum and count. sum = 0.0 count = 0 line = infile.readline() while line != "": #update sum and count for values in line print("\nThe average of the numbers is", sum/count) Python Programming, 2/e
Nested Loops In the next level in we need to update the sum and count in the body of the loop. Since each line of the file contains one or more numbers separated by commas, we can split the string into substrings, each of which represents a number. Then we need to loop through the substrings, convert each to a number, and add it to sum. We also need to update count. Python Programming, 2/e
Nested Loops for xStr in line.split(","): sum = sum + eval(xStr) count = count + 1 Notice that this for statement uses line, which is also the loop control variable for the outer loop. Python Programming, 2/e
Nested Loops # average7.py # Computes the average of numbers listed in a file. # Works with multiple numbers on a line. import string def main(): fileName = input("What file are the numbers in? ") infile = open(fileName,'r') sum = 0.0 count = 0 line = infile.readline() while line != "": for xStr in line.split(","): sum = sum + eval(xStr) count = count + 1 print("\nThe average of the numbers is", sum / count) Python Programming, 2/e
Nested Loops The loop that processes the numbers in each line is indented inside of the file processing loop. The outer while loop iterates once for each line of the file. For each iteration of the outer loop, the inner for loop iterates as many times as there are numbers on the line. When the inner loop finishes, the next line of the file is read, and this process begins again. Python Programming, 2/e
Nested Loops Designing nested loops – Design the outer loop without worrying about what goes inside Design what goes inside, ignoring the outer loop. Put the pieces together, preserving the nesting. Python Programming, 2/e
Computing with Booleans if and while both use Boolean expressions. Boolean expressions evaluate to True or False. So far we’ve used Boolean expressions to compare two values, e.g. (while x >= 0) Python Programming, 2/e
Boolean Operators Sometimes our simple expressions do not seem expressive enough. Suppose you need to determine whether two points are in the same position – their x coordinates are equal and their y coordinates are equal. Python Programming, 2/e
Boolean Operators if p1.getX() == p2.getX(): if p1.getY() == p2.getY(): # points are the same else: # points are different else: # points are different Clearly, this is an awkward way to evaluate multiple Boolean expressions! Let’s check out the three Boolean operators and, or, and not. Python Programming, 2/e
Boolean Operators The Boolean operators and and or are used to combine two Boolean expressions and produce a Boolean result. <expr> and <expr> <expr> or <expr> Python Programming, 2/e
Boolean Operators The and of two expressions is true exactly when both of the expressions are true. We can represent this in a truth table. P Q P and Q T F Python Programming, 2/e
Boolean Expressions In the truth table, P and Q represent smaller Boolean expressions. Since each expression has two possible values, there are four possible combinations of values. The last column gives the value of P and Q. Python Programming, 2/e
Boolean Expressions The or of two expressions is true when either expression is true. P Q P or Q T F Python Programming, 2/e
Boolean Expressions The only time or is false is when both expressions are false. Also, note that or is true when both expressions are true. This isn’t how we normally use “or” in language. Python Programming, 2/e
Boolean Operators The not operator computes the opposite of a Boolean expression. not is a unary operator, meaning it operates on a single expression. P not P T F Python Programming, 2/e
Boolean Operators We can put these operators together to make arbitrarily complex Boolean expressions. The interpretation of the expressions relies on the precedence rules for the operators. Python Programming, 2/e
Boolean Operators Consider a or not b and c How should this be evaluated? The order of precedence, from high to low, is not, and, or. This statement is equivalent to (a or ((not b) and c)) Since most people don’t memorize the the Boolean precedence rules, use parentheses to prevent confusion. Python Programming, 2/e
Boolean Operators To test for the co-location of two points, we could use an and. if p1.getX() == p2.getX() and p2.getY() == p1.getY(): # points are the same else: # points are different The entire condition will be true only when both of the simpler conditions are true. Python Programming, 2/e
Boolean Operators Say you’re writing a racquetball simulation. The game is over as soon as either player has scored 15 points. How can you represent that in a Boolean expression? scoreA == 15 or scoreB == 15 When either of the conditions becomes true, the entire expression is true. If neither condition is true, the expression is false. Python Programming, 2/e
Boolean Operators We want to construct a loop that continues as long as the game is not over. You can do this by taking the negation of the game-over condition as your loop condition! while not(scoreA == 15 or scoreB == 15): #continue playing Python Programming, 2/e
Boolean Operators Some racquetball players also use a shutout condition to end the game, where if one player has scored 7 points and the other person hasn’t scored yet, the game is over. while not(scoreA == 15 or scoreB == 15 or \ (scoreA == 7 and scoreB == 0) or (scoreB == 7 and scoreA == 0): #continue playing Python Programming, 2/e
Boolean Operators Let’s look at volleyball scoring. To win, a volleyball team needs to win by at least two points. In volleyball, a team wins at 15 points If the score is 15 – 14, play continues, just as it does for 21 – 20. (a >= 15 and a - b >= 2) or (b >= 15 and b - a >= 2) (a >= 15 or b >= 15) and abs(a - b) >= 2 Python Programming, 2/e
Boolean Algebra The ability to formulate, manipulate, and reason with Boolean expressions is an important skill. Boolean expressions obey certain algebraic laws called Boolean logic or Boolean algebra. Python Programming, 2/e
Boolean Algebra Algebra Boolean algebra a * 0 = 0 a and false == false a and true == a a + 0 = a a or false == a and has properties similar to multiplication or has properties similar to addition 0 and 1 correspond to false and true, respectively. Python Programming, 2/e
Boolean Algebra Anything ored with true is true: a or true == true Both and and or distribute: a or (b and c) == (a or b) and (a or c) a and (b or c) == (a and b) or (a and c) Double negatives cancel out: not(not a) == a DeMorgan’s laws: not(a or b) == (not a) and (not b) not(a and b) == (not a) or (not b) Python Programming, 2/e
Boolean Algebra We can use these rules to simplify our Boolean expressions. while not(scoreA == 15 or scoreB == 15): #continue playing This is saying something like “While it is not the case that player A has 15 or player B has 15, continue playing.” Applying DeMorgan’s law: while (not scoreA == 15) and (not scoreB == 15): #continue playing Python Programming, 2/e
Boolean Algebra This becomes: while scoreA != 15 and scoreB != 15 # continue playing Isn’t this easier to understand? “While player A has not reached 15 and player B has not reached 15, continue playing.” Python Programming, 2/e
Boolean Algebra Sometimes it’s easier to figure out when a loop should stop, rather than when the loop should continue. In this case, write the loop termination condition and put a not in front of it. After a couple applications of DeMorgan’s law you are ready to go with a simpler but equivalent expression. Python Programming, 2/e
Other Common Structures The if and while can be used to express every conceivable algorithm. For certain problems, an alternative structure can be convenient. Python Programming, 2/e
Post-Test Loop Say we want to write a program that is supposed to get a nonnegative number from the user. If the user types an incorrect input, the program asks for another value. This process continues until a valid value has been entered. This process is input validation. Python Programming, 2/e
Post-Test Loop repeat get a number from the user until number is >= 0 Python Programming, 2/e
Post-Test Loop When the condition test comes after the body of the loop it’s called a post-test loop. A post-test loop always executes the body of the code at least once. Python doesn’t have a built-in statement to do this, but we can do it with a slightly modified while loop. Python Programming, 2/e
Post-Test Loop We seed the loop condition so we’re guaranteed to execute the loop once. number = -1 while number < 0: number = eval(input("Enter a positive number: ")) By setting number to –1, we force the loop body to execute at least once. Python Programming, 2/e
Post-Test Loop Some programmers prefer to simulate a post-test loop by using the Python break statement. Executing break causes Python to immediately exit the enclosing loop. break is sometimes used to exit what looks like an infinite loop. Python Programming, 2/e
Post-Test Loop The same algorithm implemented with a break: while True: number = eval(input("Enter a positive number: ")) if x >= 0: break # Exit loop if number is valid A while loop continues as long as the expression evaluates to true. Since True always evaluates to true, it looks like an infinite loop! Python Programming, 2/e
Post-Test Loop When the value of x is nonnegative, the break statement executes, which terminates the loop. If the body of an if is only one line long, you can place it right after the :! Wouldn’t it be nice if the program gave a warning when the input was invalid? Python Programming, 2/e
Post-Test Loop In the while loop version, this is awkward: number = -1 while number < 0: number = eval(input("Enter a positive number: ")) if number < 0: print("The number you entered was not positive") We’re doing the validity check in two places! Python Programming, 2/e
Post-Test Loop Adding the warning to the break version only adds an else statement: while True: number = eval(input("Enter a positive number: ")) if x >= 0: break # Exit loop if number is valid else: print("The number you entered was not positive.") Python Programming, 2/e
Loop and a Half Stylistically, some programmers prefer the following approach: while True: number = eval(input("Enter a positive number: ")) if x >= 0: break # Loop exit print("The number you entered was not positive") Here the loop exit is in the middle of the loop body. This is what we mean by a loop and a half. Python Programming, 2/e
Loop and a Half The loop and a half is an elegant way to avoid the priming read in a sentinel loop. while True: get next data item if the item is the sentinel: break process the item This method is faithful to the idea of the sentinel loop, the sentinel value is not processed! Python Programming, 2/e
Loop and a Half Python Programming, 2/e
Loop and a Half To use or not use break. That is the question! The use of break is mostly a matter of style and taste. Avoid using break often within loops, because the logic of a loop is hard to follow when there are multiple exits. Python Programming, 2/e
Boolean Expressions as Decisions Boolean expressions can be used as control structures themselves. Suppose you’re writing a program that keeps going as long as the user enters a response that starts with ‘y’ (like our interactive loop). One way you could do it: while response[0] == "y" or response[0] == "Y": Python Programming, 2/e
Boolean Expressions as Decisions Be careful! You can’t take shortcuts: while response[0] == "y" or "Y": Why doesn’t this work? Python has a bool type that internally uses 1 and 0 to represent True and False, respectively. The Python condition operators, like ==, always evaluate to a value of type bool. Python Programming, 2/e
Boolean Expressions as Decisions However, Python will let you evaluate any built-in data type as a Boolean. For numbers (int, float, and long ints), zero is considered False, anything else is considered True. Python Programming, 2/e
Boolean Expressions as Decisions False >>> bool(1) True >>> bool(32) >>> bool("Hello") >>> bool("") >>> bool([1,2,3]) >>> bool([]) Python Programming, 2/e
Boolean Expressions as Decisions An empty sequence is interpreted as False while any non-empty sequence is taken to mean True. The Boolean operators have operational definitions that make them useful for other purposes. Python Programming, 2/e
Boolean Expressions as Decisions Operator Operational definition x and y If x is false, return x. Otherwise, return y. x or y If x is true, return x. Otherwise, return y. not x If x is false, return True. Otherwise, return False. Python Programming, 2/e
Boolean Expressions as Decisions Consider x and y. In order for this to be true, both x and y must be true. As soon as one of them is found to be false, we know the expression as a whole is false and we don’t need to finish evaluating the expression. So, if x is false, Python should return a false result, namely x. Python Programming, 2/e
Boolean Expressions as Decisions If x is true, then whether the expression as a whole is true or false depends on y. By returning y, if y is true, then true is returned. If y is false, then false is returned. Python Programming, 2/e
Boolean Expressions as Decisions These definitions show that Python’s Booleans are short-circuit operators, meaning that a true or false is returned as soon as the result is known. In an and where the first expression is false and in an or, where the first expression is true, Python will not evaluate the second expression. Python Programming, 2/e
Boolean Expressions as Decisions response[0] == "y" or "Y“ The Boolean operator is combining two operations. Here’s an equivalent expression: (response[0] == "y") or ("Y") By the operational description of or, this expression returns either True, if response[0] equals “y”, or “Y”, both of which are interpreted by Python as true. Python Programming, 2/e
Boolean Expressions as Decisions Sometimes we write programs that prompt for information but offer a default value obtained by simply pressing <Enter> Since the string used by ans can be treated as a Boolean, the code can be further simplified. Python Programming, 2/e
Boolean Expressions as Decisions ans = input("What flavor fo you want [vanilla]: ") if ans: flavor = ans else: flavor = "vanilla" If the user just hits <Enter>, ans will be an empty string, which Python interprets as false. Python Programming, 2/e
Boolean Expressions as Decisions We can code this even more succinctly! ans = input("What flavor fo you want [vanilla]: ") flavor = ans or "vanilla“ Remember, any non-empty answer is interpreted as True. This exercise could be boiled down into one line! flavor = input("What flavor do you want [vanilla]:” ) or "vanilla" Python Programming, 2/e
Boolean Expressions as Decisions Again, if you understand this method, feel free to utilize it. Just make sure that if your code is tricky, that it’s well documented! Python Programming, 2/e
Python Programming: An Introduction to Computer Science Chapter 9 Simulation and Design Python Programming, 2/e
Objectives To understand the potential applications of simulation as a way to solve real-world problems. To understand pseudorandom numbers and their application in Monte Carlo simulations. To understand and be able to apply top-down and spiral design techniques in writing complex programs. Python Programming, 2/e
Objectives To understand unit-testing and be able to apply this technique in the implementation and debugging of complex programming. Python Programming, 2/e
Simulating Racquetball Simulation can solve real-world problems by modeling real-world processes to provide otherwise unobtainable information. Computer simulation is used to predict the weather, design aircraft, create special effects for movies, etc. Python Programming, 2/e
A Simulation Problem Denny Dibblebit often plays racquetball with players who are slightly better than he is. Denny usually loses his matches! Shouldn’t players who are a little better win a little more often? Susan suggests that they write a simulation to see if slight differences in ability can cause such large differences in scores. Python Programming, 2/e
Analysis and Specification Racquetball is played between two players using a racquet to hit a ball in a four-walled court. One player starts the game by putting the ball in motion – serving. Players try to alternate hitting the ball to keep it in play, referred to as a rally. The rally ends when one player fails to hit a legal shot. Python Programming, 2/e
Analysis and Specification The player who misses the shot loses the rally. If the loser is the player who served, service passes to the other player. If the server wins the rally, a point is awarded. Players can only score points during their own service. The first player to reach 15 points wins the game. Python Programming, 2/e
Analysis and Specification In our simulation, the ability level of the players will be represented by the probability that the player wins the rally when he or she serves. Example: Players with a 0.60 probability win a point on 60% of their serves. The program will prompt the user to enter the service probability for both players and then simulate multiple games of racquetball. The program will then print a summary of the results. Python Programming, 2/e Python Programming, 1/e
Analysis and Specification Input: The program prompts for and gets the service probabilities of players A and B. The program then prompts for and gets the number of games to be simulated. Python Programming, 2/e
Analysis and Specification Output: The program will provide a series of initial prompts such as the following: What is the probability player A wins a serve? What is the probability that player B wins a server? How many games to simulate? The program then prints out a nicely formatted report showing the number of games simulated and the number of wins and the winning percentage for each player. Games simulated: 500 Wins for A: 268 (53.6%) Wins for B: 232 (46.4%) Python Programming, 2/e
Analysis and Specification Notes: All inputs are assumed to be legal numeric values, no error or validity checking is required. In each simulated game, player A serves first. Python Programming, 2/e
PseudoRandom Numbers When we say that player A wins 50% of the time, that doesn’t mean they win every other game. Rather, it’s more like a coin toss. Overall, half the time the coin will come up heads, the other half the time it will come up tails, but one coin toss does not effect the next (it’s possible to get 5 heads in a row). Python Programming, 2/e
PseudoRandom Numbers Many simulations require events to occur with a certain likelihood. These sorts of simulations are called Monte Carlo simulations because the results depend on “chance” probabilities. Do you remember the chaos program from chapter 1? The apparent randomness of the result came from repeatedly applying a function to generate a sequence of numbers. Python Programming, 2/e
PseudoRandom Numbers A similar approach is used to generate random (technically pseudorandom) numbers. A pseudorandom number generator works by starting with a seed value. This value is given to a function to produce a “random” number. The next time a random number is required, the current value is fed back into the function to produce a new number. Python Programming, 2/e
PseudoRandom Numbers This sequence of numbers appears to be random, but if you start the process over again with the same seed number, you’ll get the same sequence of “random” numbers. Python provides a library module that contains a number of functions for working with pseudorandom numbers. Python Programming, 2/e
PseudoRandom Numbers These functions derive an initial seed value from the computer’s date and time when the module is loaded, so each time a program is run a different sequence of random numbers is produced. The two functions of greatest interest are randrange and random. Python Programming, 2/e
PseudoRandom Numbers The randrange function is used to select a pseudorandom int from a given range. The syntax is similar to that of the range command. randrange(1,6) returns some number from [1,2,3,4,5] and randrange(5,105,5) returns a multiple of 5 between 5 and 100, inclusive. Ranges go up to, but don’t include, the stopping value. Python Programming, 2/e
PseudoRandom Numbers Each call to randrange generates a new pseudorandom int. >>> from random import randrange >>> randrange(1,6) 5 3 2 4 Python Programming, 2/e
PseudoRandom Numbers The value 5 comes up over half the time, demonstrating the probabilistic nature of random numbers. Over time, this function will produce a uniform distribution, which means that all values will appear an approximately equal number of times. Python Programming, 2/e
PseudoRandom Numbers The random function is used to generate pseudorandom floating point values. It takes no parameters and returns values uniformly distributed between 0 and 1 (including 0 but excluding 1). Python Programming, 2/e
PseudoRandom Numbers >>> from random import random 0.79432800912898816 0.00049858619405451776 0.1341231400816878 0.98724554535361653 0.21429424175032197 0.23903583712127141 0.72918328843408919 Python Programming, 2/e
PseudoRandom Numbers The racquetball simulation makes use of the random function to determine if a player has won a serve. Suppose a player’s service probability is 70%, or 0.70. if <player wins serve>: score = score + 1 We need to insert a probabilistic function that will succeed 70% of the time. Python Programming, 2/e
PseudoRandom Numbers Suppose we generate a random number between 0 and 1. Exactly 70% of the interval 0..1 is to the left of 0.7. So 70% of the time the random number will be < 0.7, and it will be ≥ 0.7 the other 30% of the time. (The = goes on the upper end since the random number generator can produce a 0 but not a 1.) Python Programming, 2/e
PseudoRandom Numbers If prob represents the probability of winning the server, the condition random() < prob will succeed with the correct probability. if random() < prob: score = score + 1 Python Programming, 2/e
Top-Down Design In top-down design, a complex problem is expressed as a solution in terms of smaller, simpler problems. These smaller problems are then solved by expressing them in terms of smaller, simpler problems. This continues until the problems are trivial to solve. The little pieces are then put back together as a solution to the original problem! Python Programming, 2/e
Top-Level Design Typically a program uses the input, process, output pattern. The algorithm for the racquetball simulation: Print an introduction Get the inputs: probA, probB, n Simulate n games of racquetball using probA and probB Print a report on the wins for playerA and playerB Python Programming, 2/e
Top-Level Design Is this design too high level? Whatever we don’t know how to do, we’ll ignore for now. Assume that all the components needed to implement the algorithm have been written already, and that your task is to finish this top-level algorithm using those components. Python Programming, 2/e
Top-Level Design First we print an introduction. This is easy, and we don’t want to bother with it. def main(): printIntro() We assume that there’s a printIntro function that prints the instructions! Python Programming, 2/e
Top-Level Design The next step is to get the inputs. We know how to do that! Let’s assume there’s already a component that can do that called getInputs. getInputs gets the values for probA, probB, and n. def main(): printIntro() probA, probB, n = getInputs() Python Programming, 2/e
Top-Level Design Now we need to simulate n games of racquetball using the values of probA and probB. How would we do that? We can put off writing this code by putting it into a function, simNGames, and add a call to this function in main. Python Programming, 2/e
Top-Level Design If you were going to simulate the game by hand, what inputs would you need? probA probB n What values would you need to get back? The number of games won by player A The number of games won by player B These must be the outputs from the simNGames function. Python Programming, 2/e
Top-Level Design We now know that the main program must look like this: def main(): printIntro() probA, probB, n = getInputs() winsA, winsB = simNGames(n, probA, probB) What information would you need to be able to produce the output from the program? You’d need to know how many wins there were for each player – these will be the inputs to the next function. Python Programming, 2/e
Top-Level Design The complete main program: def main(): printIntro() probA, probB, n = getInputs() winsA, winsB = simNGames(n, probA, probB) printSummary(winsA, winsB) Python Programming, 2/e
Separation of Concerns The original problem has now been decomposed into four independent tasks: printIntro getInputs simNGames printSummary The name, parameters, and expected return values of these functions have been specified. This information is known as the interface or signature of the function. Python Programming, 2/e
Separation of Concerns Having this information (the signatures), allows us to work on each of these pieces indepently. For example, as far as main is concerned, how simNGames works is not a concern as long as passing the number of games and player probabilities to simNGames causes it to return the correct number of wins for each player. Python Programming, 2/e
Separation of Concerns In a structure chart (or module hierarchy), each component in the design is a rectangle. A line connecting two rectangles indicates that the one above uses the one below. The arrows and annotations show the interfaces between the components. Python Programming, 2/e
Separation of Concerns Python Programming, 2/e
Separation of Concerns At each level of design, the interface tells us which details of the lower level are important. The general process of determining the important characteristics of something and ignoring other details is called abstraction. The top-down design process is a systematic method for discovering useful abstractions. Python Programming, 2/e
Second-Level Design The next step is to repeat the process for each of the modules defined in the previous step! The printIntro function should print an introduction to the program. The code for this is straightforward. Python Programming, 2/e
Second-Level Design def printIntro(): # Prints an introduction to the program print("This program simulates a game of racquetball between two") print('players called "A" and "B". The abilities of each player is') print("indicated by a probability (a number between 0 and 1) that") print("the player wins the point when serving. Player A always") print("has the first serve.\n“) In the second line, since we wanted double quotes around A and B, the string is enclosed in apostrophes. Since there are no new functions, there are no changes to the structure chart. Python Programming, 2/e
Second-Level Design In getInputs, we prompt for and get three values, which are returned to the main program. def getInputs(): # RETURNS probA, probB, number of games to simulate a = eval(input("What is the prob. player A wins a serve? ")) b = eval(input("What is the prob. player B wins a serve? ")) n = eval(input("How many games to simulate? ")) return a, b, n Python Programming, 2/e
Designing simNGames This function simulates n games and keeps track of how many wins there are for each player. “Simulate n games” sound like a counted loop, and tracking wins sounds like a good job for accumulator variables. Python Programming, 2/e
Designing simNGames Initialize winsA and winsB to 0 loop n times simulate a game if playerA wins Add one to winsA else Add one to winsB Python Programming, 2/e
Designing simNGames We already have the function signature: def simNGames(n, probA, probB): # Simulates n games of racquetball between players A and B # RETURNS number of wins for A, number of wins for B With this information, it’s easy to get started! def simNGames(n, probA, probB): # Simulates n games of racquetball between players A and B # RETURNS number of wins for A, number of wins for B winsA = 0 winsB = 0 for i in range(n): Python Programming, 2/e
Designing simNGames The next thing we need to do is simulate a game of racquetball. We’re not sure how to do that, so let’s put it off until later! Let’s assume there’s a function called simOneGame that can do it. The inputs to simOneGame are easy – the probabilities for each player. But what is the output? Python Programming, 2/e
Designing simNGames We need to know who won the game. How can we get this information? The easiest way is to pass back the final score. The player with the higher score wins and gets their accumulator incremented by one. Python Programming, 2/e
Designing simNGames def simNGames(n, probA, probB): # Simulates n games of racquetball between players A and B # RETURNS number of wins for A, number of wins for B winsA = winsB = 0 for i in range(n): scoreA, scoreB = simOneGame(probA, probB) if scoreA > scoreB: winsA = winsA + 1 else: winsB = winsB + 1 return winsA, winsB Python Programming, 2/e
Designing simNGames Python Programming, 2/e
Third-Level Design The next function we need to write is simOneGame, where the logic of the racquetball rules lies. Players keep doing rallies until the game is over, which implies the use of an indefinite loop, since we don’t know ahead of time how many rallies there will be before the game is over. Python Programming, 2/e
Third-Level Design We also need to keep track of the score and who’s serving. The score will be two accumulators, so how do we keep track of who’s serving? One approach is to use a string value that alternates between “A” or “B”. Python Programming, 2/e
Third-Level Design Initialize scores to 0 Set serving to “A” Loop while game is not over: Simulate one serve of whichever player is serving update the status of the game Return scores Def simOneGame(probA, probB): scoreA = 0 scoreB = 0 serving = “A” while <condition>: What will the condition be?? Let’s take the two scores and pass them to another function that returns True if the game is over, False if not. Python Programming, 2/e
Third-Level Design Python Programming, 2/e
Third-Level Design At this point, simOneGame looks like this: def simOneGame(probA, probB): # Simulates a single game or racquetball between players A and B # RETURNS A's final score, B's final score serving = "A“ scoreA = 0 scoreB = 0 while not gameOver(scoreA, scoreB): Python Programming, 2/e
Third-Level Design Inside the loop, we need to do a single serve. We’ll compare a random number to the provided probability to determine if the server wins the point (random() < prob). The probability we use is determined by whom is serving, contained in the variable serving. Python Programming, 2/e
Third-Level Design If A is serving, then we use A’s probability, and based on the result of the serve, either update A’s score or change the service to B. if serving == "A": if random() < probA: scoreA = scoreA + 1 else: serving = "B" Python Programming, 2/e
Third-Level Design Likewise, if it’s B’s serve, we’ll do the same thing with a mirror image of the code. if serving == "A": if random() < probA: scoreA = scoreA + 1 else: serving = "B“ else: if random() < probB: scoreB = scoreB + 1 else: serving = "A" Python Programming, 2/e
Third-Level Design Putting the function together: def simOneGame(probA, probB): # Simulates a single game or racquetball between players A and B # RETURNS A's final score, B's final score serving = "A" scoreA = 0 scoreB = 0 while not gameOver(scoreA, scoreB): if serving == "A": if random() < probA: scoreA = scoreA + 1 else: serving = "B" if random() < probB: scoreB = scoreB + 1 return scoreA, scoreB Python Programming, 2/e
Finishing Up There’s just one tricky function left, gameOver. Here’s what we know: def gameOver(a,b): # a and b are scores for players in a racquetball game # RETURNS true if game is over, false otherwise According to the rules, the game is over when either player reaches 15 points. We can check for this with the boolean: a==15 or b==15 Python Programming, 2/e
Finishing Up So, the complete code for gameOver looks like this: def gameOver(a,b): # a and b are scores for players in a racquetball game # RETURNS true if game is over, false otherwise return a == 15 or b == 15 printSummary is equally simple! def printSummary(winsA, winsB): # Prints a summary of wins for each player. n = winsA + winsB print "\nGames simulated:", n print "Wins for A: {0} ({1:0.1%})".format(winsA, winsA)/n) print "Wins for B: {0} ({1:0.1%})".format(winsB, winsB/n) Notice % formatting on the output Python Programming, 2/e
Summary of the Design Process We started at the highest level of our structure chart and worked our way down. At each level, we began with a general algorithm and refined it into precise code. This process is sometimes referred to as step-wise refinement. Python Programming, 2/e
Summary of the Design Process Express the algorithm as a series of smaller problems. Develop an interface for each of the small problems. Detail the algorithm by expressing it in terms of its interfaces with the smaller problems. Repeat the process for each smaller problem. Python Programming, 2/e
Bottom-Up Implementation Even though we’ve been careful with the design, there’s no guarantee we haven’t introduced some silly errors. Implementation is best done in small pieces. Python Programming, 2/e
Unit Testing A good way to systematically test the implementation of a modestly sized program is to start at the lowest levels of the structure, testing each component as it’s completed. For example, we can import our program and execute various routines/functions to ensure they work properly. Python Programming, 2/e
Unit Testing We could start with the gameOver function. >>> import rball >>> rball.gameOver(0,0) False >>> rball.gameOver(5,10) False >>> rball.gameOver(15,3) True >>> rball.gameOver(3,15) True Python Programming, 2/e
Unit Testing Notice that we’ve tested gameOver for all the important cases. We gave it 0, 0 as inputs to simulate the first time the function will be called. The second test is in the middle of the game, and the function correctly reports that the game is not yet over. The last two cases test to see what is reported when either player has won. Python Programming, 2/e
Unit Testing Now that we see that gameOver is working, we can go on to simOneGame. >>> simOneGame(.5, .5) (11, 15) (13, 15) >>> simOneGame(.3, .3) (15, 4) >>> simOneGame(.4, .9) (2, 15) (1, 15) >>> simOneGame(.9, .4) (15, 0) >>> simOneGame(.4, .6) (10, 15) (9, 15) Python Programming, 2/e
Unit Testing When the probabilities are equal, the scores aren’t that far apart. When the probabilities are farther apart, the game is a rout. Testing each component in this manner is called unit testing. Testing each function independently makes it easier to spot errors, and should make testing the entire program go more smoothly. Python Programming, 2/e
Simulation Results Is it the nature of racquetball that small differences in ability lead to large differences in final score? Suppose Denny wins about 60% of his serves and his opponent is 5% better. How often should Denny win? Let’s do a sample run where Denny’s opponent serves first. Python Programming, 2/e
Simulation Results This program simulates a game of racquetball between two players called "A" and "B". The abilities of each player is indicated by a probability (a number between 0 and 1) that the player wins the point when serving. Player A always has the first serve. What is the prob. player A wins a serve? .65 What is the prob. player B wins a serve? .6 How many games to simulate? 5000 Games simulated: 5000 Wins for A: 3329 (66.6%) Wins for B: 1671 (33.4%) With this small difference in ability , Denny will win only 1 in 3 games! Python Programming, 2/e
Other Design Techniques Top-down design is not the only way to create a program! Python Programming, 2/e
Prototyping and Spiral Development Another approach to program development is to start with a simple version of a program, and then gradually add features until it meets the full specification. This initial stripped-down version is called a prototype. Python Programming, 2/e
Prototyping and Spiral Development Prototyping often leads to a spiral development process. Rather than taking the entire problem and proceeding through specification, design, implementation, and testing, we first design, implement, and test a prototype. We take many mini-cycles through the development process as the prototype is incrementally expanded into the final program. Python Programming, 2/e
Prototyping and Spiral Development How could the racquetball simulation been done using spiral development? Write a prototype where you assume there’s a 50-50 chance of winning any given point, playing 30 rallies. Add on to the prototype in stages, including awarding of points, change of service, differing probabilities, etc. Python Programming, 2/e
Prototyping and Spiral Development from random import random def simOneGame(): scoreA = 0 scoreB = 0 serving = "A" for i in range(30): if serving == "A": if random() < .5: scoreA = scoreA + 1 else: serving = "B" scoreB = scoreB + 1 print(scoreA, scoreB) >>> simOneGame() 0 0 0 1 … 2 7 2 8 3 8 3 9 4 9 5 9 Python Programming, 2/e
Prototyping and Spiral Development The program could be enhanced in phases: Phase 1: Initial prototype. Play 30 rallies where the server always has a 50% chance of winning. Print out the scores after each server. Phase 2: Add two parameters to represent different probabilities for the two players. Python Programming, 2/e
Prototyping and Spiral Development Phase 3: Play the game until one of the players reaches 15 points. At this point, we have a working simulation of a single game. Phase 4: Expand to play multiple games. The output is the count of games won by each player. Phase 5: Build the complete program. Add interactive inputs and a nicely formatted report of the results. Python Programming, 2/e
Prototyping and Spiral Development Spiral development is useful when dealing with new or unfamiliar features or technology. If top-down design isn’t working for you, try some spiral development! Python Programming, 2/e
The Art of Design Spiral development is not an alternative to top-down design as much as a complement to it – when designing the prototype you’ll still be using top-down techniques. Good design is as much creative process as science, and as such, there are no hard and fast rules. Python Programming, 2/e
The Art of Design The best advice? Practice, practice, practice Python Programming, 2/e
Python Programming: An Introduction To Computer Science Chapter 10 Defining Classes Python Programming, 2/e
Objectives To appreciate how defining new classes can provide structure for a complex program. To be able to read and write Python class definitions. To understand the concept of encapsulation and how it contributes to building modular and maintainable programs. Python Programming, 2/e Python Programming, 1/e
Objectives To be able to write programs involving simple class definitions. To be able to write interactive graphics programs involving novel (programmer designed) widgets. Python Programming, 2/e
Quick Review of Objects In the last three chapters we’ve developed techniques for structuring the computations of the program. We’ll now take a look at techniques for structuring the data that our programs use. So far, our programs have made use of objects created from pre-defined class such as Circle. In this chapter we’ll learn how to write our own classes to create novel objects. Python Programming, 2/e
Quick Review of Objects In chapter five an object was defined as an active data type that knows stuff and can do stuff. More precisely, an object consists of: A collection of related information. A set of operations to manipulate that information. Python Programming, 2/e
Quick Review of Objects The information is stored inside the object in instance variables. The operations, called methods, are functions that “live” inside the object. Collectively, the instance variables and methods are called the attributes of an object. Python Programming, 2/e
Quick Review of Objects A Circle object will have instance variables such as center, which remembers the center point of the circle, and radius, which stores the length of the circle’s radius. The draw method examines the center and radius to decide which pixels in a window should be colored. Python Programming, 2/e
Quick Review of Objects The move method will change the value of center to reflect the new position of the circle. All objects are said to be an instance of some class. The class of an object determines which attributes the object will have. A class is a description of what its instances will know and do. Python Programming, 2/e
Quick Review of Objects New objects are created from a class by invoking a constructor. You can think of the class itself as a sort of factory for stamping out new instances. Consider making a new circle object: myCircle = Circle(Point(0,0),20) Circle, the name of the class, is used to invoke the constructor. Python Programming, 2/e
Quick Review of Objects myCircle = Circle(Point(0,0), 20) This statement creates a new Circle instance and stores a reference to it in the variable myCircle. The parameters to the constructor are used to initialize some of the instance variables (center and radius) inside myCircle. Python Programming, 2/e
Quick Review of Objects myCircle = Circle(Point(0,0), 20) Once the instance has been created, it can be manipulated by calling on its methods: myCircle.draw(win) myCircle.move(dx,dy) Python Programming, 2/e
Cannonball Program Specification Let’s try to write a program that simulates the flight of a cannonball or other projectile. We’re interested in how far the cannonball will travel when fired at various launch angles and initial velocities. Python Programming, 2/e
Cannonball Program Specification The input to the program will be the launch angle (in degrees), the initial velocity (in meters per second), and the initial height (in meters) of the cannonball. The output will be the distance that the projectile travels before striking the ground (in meters). Python Programming, 2/e
Cannonball Program Specification The acceleration of gravity near the earth’s surface is roughly 9.8 m/s/s. If an object is thrown straight up at 20 m/s, after one second it will be traveling upwards at 10.2 m/s. After another second, its speed will be .4 m/s. Shortly after that the object will start coming back down to earth. Python Programming, 2/e
Cannonball Program Specification Using calculus, we could derive a formula that gives the position of the cannonball at any moment of its flight. However, we’ll solve this problem with simulation, a little geometry, and the fact that the distance an object travels in a certain amount of time is equal to its rate times the amount of time (d = rt). Python Programming, 2/e
Designing the Program Given the nature of the problem, it’s obvious we need to consider the flight of the cannonball in two dimensions: it’s height and the distance it travels. Let’s think of the position of the cannonball as the point (x, y) where x is the distance from the starting point and y is the height above the ground. Python Programming, 2/e
Designing the Program Suppose the ball starts at position (0,0), and we want to check its position every tenth of a second. In that time interval it will have moved some distance upward (positive y) and some distance forward (positive x). The exact distance will be determined by the velocity in that direction. Python Programming, 2/e
Designing the Program Since we are ignoring wind resistance, x will remain constant through the flight. However, y will change over time due to gravity. The y velocity will start out positive and then become negative as the ball starts to fall. Python Programming, 2/e
Designing the Program Input the simulation parameters: angle, velocity, height, interval. Calculate the initial position of the cannonball: xpos, ypos Calculate the initial velocities of the cannonball: xvel, yvel While the cannonball is still flying: Update the values of xpos, ypos, and yvel for interval seconds further into the flight Output the distance traveled as xpos Python Programming, 2/e
Designing the Program Using step-wise refinement: def main(): angle = eval(input("Enter the launch angle (in degrees): ")) vel = eval(input("Enter the initial velocity (in meters/sec): ")) h0 = eval(input("Enter the initial height (in meters): ")) time = eval(input("Enter the time interval between position calculations: ")) Calculating the initial position for the cannonball is also easy. It’s at distance 0 and height h0! xpos = 0 ypos = h0 Python Programming, 2/e
Designing the Program If we know the magnitude of the velocity and the angle theta, we can calculate yvel=velocity*sin(theta)and xvel=velocity*cos(theta). Python Programming, 2/e
Designing the Program Our input angle is in degrees, and the Python math library uses radians, so theta = (*angle)/180. theta = (angle * pi)/180.0 xvel = vel * cos(theta) yvel = vel * sin(theta) In the main loop, we want to keep updating the position of the ball until it reaches the ground: while ypos >= 0.0: We used >= 0 so the loop will start if the ball starts out on the ground. Python Programming, 2/e
Designing the Program Each time through the loop we want to update the state of the cannonball to move it time seconds farther. Since we assume there is no wind resistance, xvel remains constant. Say a ball is traveling at 30 m/s and is 50 m from the firing point. In one second it will be 50 + 30 meters away. If the time increment is .1 second it will be 50 + 30*.1 = 53 meters. xpos = xpos + time * xvel Python Programming, 2/e
Designing the Program Working with yvel is slightly more complicated since gravity causes the y-velocity to change over time. Each second, yvel must decrease by 9.8 m/s, the acceleration due to gravity. In 0.1 seconds the velocity will be 0.1(9.8) = .98 m/s. yvel1 = yvel - 9.8 * time Python Programming, 2/e
Designing the Programs To calculate how far the cannonball travels over the interval, we need to calculate its average vertical velocity over the interval. Since the velocity due to gravity is constant, it is simply the average of the starting and ending velocities times the length of the interval: ypos = ypos + time * (yvel + yvel1)/2.0 Python Programming, 2/e
Designing Programs Python Programming, 2/e # cball1.py # Simulation of the flight of a cannon ball (or other projectile) # This version is not modularized. from math import pi, sin, cos def main(): angle = eval(input("Enter the launch angle (in degrees): ")) vel = eval(input("Enter the initial velocity (in meters/sec): ")) h0 = eval(input("Enter the initial height (in meters): ")) time = eval(input("Enter the time interval between position calculations: ")) radians = (angle * pi)/180.0 xpos = 0 ypos = h0 xvel = vel * cos(radians) yvel = vel * sin(radians) while ypos >= 0: xpos = xpos + time * xvel yvel1 = yvel - 9.8 * time ypos = ypos + time * (yvel + yvel1)/2.0 yvel = yvel1 print("\nDistance traveled: {0:0.1f} meters." .format(xpos) main() Python Programming, 2/e
Modularizing the Program During program development, we employed step-wise refinement (and top-down design), but did not divide the program into functions. While this program is fairly short, it is complex due to the number of variables. Python Programming, 2/e
Modularizing the Program def main(): angle, vel, h0, time = getInputs() xpos, ypos = 0, h0 xvel, yvel = getXYComponents(vel, angle) while ypos >= 0: xpos, ypos, yvel = updateCannonBall(time, xpos, ypos, xvel, yvel) print("\nDistance traveled: {0:0.1f} meters.".format(xpos) It should be obvious what each of these helper functions does based on their name and the original program code. Python Programming, 2/e
Modularizing the Program This version of the program is more concise! The number of variables has been reduced from 10 to 8, since theta and yvel1 are local to getXYComponents and updateCannonBall, respectively. This may be simpler, but keeping track of the cannonball still requires four pieces of information, three of which change from moment to moment! Python Programming, 2/e
Modularizing the Program All four variables, plus time, are needed to compute the new values of the three that change. This gives us a function with five parameters and three return values. Yuck! There must be a better way! Python Programming, 2/e
Modularizing the Program There is a single real-world cannonball object, but it requires four pieces of information: xpos, ypos, xvel,x and yvel. Suppose there was a Projectile class that “understood” the physics of objects like cannonballs. An algorithm using this approach would create and update an object stored in a single variable. Python Programming, 2/e
Modularizing the Program Using our object-based approach: def main(): angle, vel, h0, time = getInputs() cball = Projectile(angle, vel, h0) while cball.getY() >= 0: cball.update(time) print("\nDistance traveled: {0:0.1f} meters.".format(cball.getX())) main() To make this work we need a Projectile class that implements the methods update, getX, and getY. Python Programming, 2/e
Example: Multi-Sided Dice A normal die (singular of dice) is a cube with six faces, each with a number from one to six. Some games use special dice with a different number of sides. Let’s design a generic class MSDie to model multi-sided dice. Python Programming, 2/e
Example: Multi-Sided Dice Each MSDie object will know two things: How many sides it has. It’s current value When a new MSDie is created, we specify n, the number of sides it will have. Python Programming, 2/e
Example: Multi-Sided Dice We have three methods that we can use to operate on the die: roll – set the die to a random value between 1 and n, inclusive. setValue – set the die to a specific value (i.e. cheat) getValue – see what the current value is. Python Programming, 2/e
Example: Multi-Sided Dice >>> die1 = MSDie(6) >>> die1.getValue() 1 >>> die1.roll() 5 >>> die2 = MSDie(13) >>> die2.getValue() >>> die2.roll() 9 >>> die2.setValue(8) 8 Python Programming, 2/e
Example: Multi-Sided Dice Using our object-oriented vocabulary, we create a die by invoking the MSDie constructor and providing the number of sides as a parameter. Our die objects will keep track of this number internally as an instance variable. Another instance variable is used to keep the current value of the die. We initially set the value of the die to be 1 because that value is valid for any die. That value can be changed by the roll and setRoll methods, and returned by the getValue method. Python Programming, 2/e
Example: Multi-Sided Dice # msdie.py # Class definition for an n-sided die. from random import randrange class MSDie: def __init__(self, sides): self.sides = sides self.value = 1 def roll(self): self.value = randrange(1, self.sides+1) def getValue(self): return self.value def setValue(self, value): self.value = value Python Programming, 2/e
Example: Multi-Sided Dice Class definitions have the form class <class-name>: <method-definitions> Methods look a lot like functions! Placing the function inside a class makes it a method of the class, rather than a stand-alone function. The first parameter of a method is always named self, which is a reference to the object on which the method is acting. Python Programming, 2/e
Example: Multi-Sided Dice Suppose we have a main function that executes die1.setValue(8). Just as in function calls, Python executes the following four-step sequence: main suspends at the point of the method application. Python locates the appropriate method definition inside the class of the object to which the method is being applied. Here, control is transferred to the setValue method in the MSDie class, since die1 is an instance of MSDie. Python Programming, 2/e
Example: Multi-Sided Dice The formal parameters of the method get assigned the values supplied by the actual parameters of the call. In the case of a method call, the first formal parameter refers to the object: self = die1 value = 8 The body of the method is executed. Python Programming, 2/e
Example: Multi-Sided Dice Control returns to the point just after where the method was called. In this case, it is immediately following die1.setValue(8). Methods are called with one parameter, but the method definition itself includes the self parameter as well as the actual parameter. Python Programming, 2/e
Example: Multi-Sided Dice The self parameter is a bookkeeping detail. We can refer to the first formal parameter as the self parameter and other parameters as normal parameters. So, we could say setValue uses one normal parameter. Python Programming, 2/e
Example: Multi-Sided Dice Python Programming, 2/e
Example: Multi-Sided Dice Objects contain their own data. Instance variables provide storage locations inside of an object. Instance variables are accessed by name using our dot notation: <object>.<instance-var> Looking at setValue, we see self.value refers to the instance variable value inside the object. Each MSDie object has its own value. Python Programming, 2/e
Example: Multi-Sided Dice Certain methods have special meaning. These methods have names that start and end with two _’s. __init__ is the object contructor. Python calls this method to initialize a new MSDie. __init__ provides initial values for the instance variables of an object. Python Programming, 2/e
Example: Multi-Sided Dice Outside the class, the constructor is referred to by the class name: die1 = MSDie(6) When this statement is executed, a new MSDie object is created and __init__ is executed on that object. The net result is that die1.sides is set to 6 and die1.value is set to 1. Python Programming, 2/e
Example: Multi-Sided Dice Instance variables can remember the state of a particular object, and this information can be passed around the program as part of the object. This is different than local function variables, whose values disappear when the function terminates. Python Programming, 2/e
Example: The Projectile Class This class will need a constructor to initialize instance variables, an update method to change the state of the projectile, and getX and getY methods that can report the current position. In the main program, a cannonball can be created from the initial angle, velocity, and height: cball = Projectile(angle, vel, h0) Python Programming, 2/e
Example: The Projectile Class The Projectile class must have an __init__ method that will use these values to initialize the instance variables of cball. These values will be calculated using the same formulas as before. Python Programming, 2/e
Example: The Projectile Class class Projectile: def __init__(self, angle, velocity, height): self.xpos = 0.0 self.ypos = height theta = pi * angle / 180.0 self.xvel = velocity * cos(theta) self.yvel = velocity * sin(theta) We’ve created four instance variables (self.???). Since the value of theta is not needed later, it is a normal function variable. Python Programming, 2/e
Example: The Projectile Class The methods to access the X and Y position are straightforward. def getY(self): return self.ypos def getX(self): return self.xpos Python Programming, 2/e
Example: The Projectile Class The last method is update, where we’ll take the time interval and calculate the update X and Y values. def update(self, time): self.xpos = self.xpos + time * self.xvel yvel1 = self.yvel - 9.8 * time self.ypos = self.ypos + time * (self.yvel + yvel1) / 2.0 self.yvel = yvel1 yvel1 is a temporary variable. Python Programming, 2/e
Data Processing with Class A class is useful for modeling a real-world object with complex behavior. Another common use for objects is to group together a set of information that describes a person or thing. Eg., a company needs to keep track of information about employees (an Employee class with information such as employee’s name, social security number, address, salary, etc.) Python Programming, 2/e
Data Processing with Class Grouping information like this is often called a record. Let’s try a simple data processing example! A typical university measures courses in terms of credit hours, and grade point averages are calculated on a 4 point scale where an “A” is 4 points, a “B” is three, etc. Python Programming, 2/e
Data Processing with Class Grade point averages are generally computed using quality points. If a class is worth 3 credit hours and the student gets an “A”, then he or she earns 3(4) = 12 quality points. To calculate the GPA, we divide the total quality points by the number of credit hours completed. Python Programming, 2/e
Data Processing with Class Suppose we have a data file that contains student grade information. Each line of the file consists of a student’s name, credit-hours, and quality points. Adams, Henry 127 228 Comptewell, Susan 100 400 DibbleBit, Denny 18 41.5 Jones, Jim 48.5 155 Smith, Frank 37 125.33 Python Programming, 2/e
Data Processing with Class Our job is to write a program that reads this file to find the student with the best GPA and print out their name, credit-hours, and GPA. The place to start? Creating a Student class! We can use a Student object to store this information as instance variables. Python Programming, 2/e
Data Processing with Class class Student: def __init__(self, name, hours, qpoints): self.name = name self.hours = float(hours) self.qpoints = float(qpoints) The values for hours are converted to float to handle parameters that may be floats, ints, or strings. To create a student record: aStudent = Student(“Adams, Henry”, 127, 228) The coolest thing is that we can store all the information about a student in a single variable! Python Programming, 2/e
Data Processing with Class We need to be able to access this information, so we need to define a set of accessor methods. def getName(self): return self.name def getHours(self): return self.hours def getQPoints(self): return self.qpoints def gpa(self): return self.qpoints/self.hours For example, to print a student’s name you could write: print aStudent.getName() Python Programming, 2/e
Data Processing with Class How can we use these tools to find the student with the best GPA? We can use an algorithm similar to finding the max of n numbers! We could look through the list one by one, keeping track of the best student seen so far! Python Programming, 2/e
Data Processing with Class Get the file name from the user Open the file for reading Set best to be the first student For each student s in the file if s.gpa() > best.gpa set best to s Print out information about best Python Programming, 2/e
Data Processing with Class # gpa.py # Program to find student with highest GPA class Student: def __init__(self, name, hours, qpoints): self.name = name self.hours = float(hours) self.qpoints = float(qpoints) def getName(self): return self.name def getHours(self): return self.hours def getQPoints(self): return self.qpoints def gpa(self): return self.qpoints/self.hours def makeStudent(infoStr): name, hours, qpoints = infoStr.split("\t") return Student(name, hours, qpoints) def main(): filename = input("Enter name the grade file: ") infile = open(filename, 'r') best = makeStudent(infile.readline()) for line in infile: s = makeStudent(line) if s.gpa() > best.gpa(): best = s infile.close() print("The best student is:", best.getName()) print ("hours:", best.getHours()) print("GPA:", best.gpa()) if __name__ == '__main__': main() Python Programming, 2/e
Encapsulating Useful Abstractions Defining new classes (like Projectile and Student) can be a good way to modularize a program. Once some useful objects are identified, the implementation details of the algorithm can be moved into a suitable class definition. Python Programming, 2/e
Encapsulating Useful Abstractions The main program only has to worry about what objects can do, not about how they are implemented. In computer science, this separation of concerns is known as encapsulation. The implementation details of an object are encapsulated in the class definition, which insulates the rest of the program from having to deal with them. Python Programming, 2/e
Encapsulating Useful Abstractions One of the main reasons to use objects is to hide the internal complexities of the objects from the programs that use them. From outside the class, all interaction with an object can be done using the interface provided by its methods. Python Programming, 2/e
Encapsulating Useful Abstractions One advantage of this approach is that it allows us to update and improve classes independently without worrying about “breaking” other parts of the program, provided that the interface provided by the methods does not change. Python Programming, 2/e
Putting Classes in Modules Sometimes we may program a class that could useful in many other programs. If you might be reusing the code again, put it into its own module file with documentation to describe how the class can be used so that you won’t have to try to figure it out in the future from looking at the code! Python Programming, 2/e
Module Documentation You are already familiar with “#” to indicate comments explaining what’s going on in a Python file. Python also has a special kind of commenting convention called the docstring. You can insert a plain string literal as the first line of a module, class, or function to document that component. Python Programming, 2/e
Module Documentation Why use a docstring? Ordinary comments are ignored by Python Docstrings are accessible in a special attribute called __doc__. Most Python library modules have extensive docstrings. For example, if you can’t remember how to use random: >>> import random >>> print random.random.__doc__ random() -> x in the interval [0, 1). Python Programming, 2/e
Module Documentation Docstrings are also used by the Python online help system and by a utility called PyDoc that automatically builds documentation for Python modules. You could get the same information like this: >>> import random >>> help(random.random) Help on built-in function random: random(...) random() -> x in the interval [0, 1). Python Programming, 2/e
Module Documentation To see the documentation for an entire module, try typing help(module_name)! The following code for the projectile class has docstrings. Python Programming, 2/e
Module Documentation Python Programming, 2/e # projectile.py Provides a simple class for modeling the flight of projectiles.""" from math import pi, sin, cos class Projectile: """Simulates the flight of simple projectiles near the earth's surface, ignoring wind resistance. Tracking is done in two dimensions, height (y) and distance (x).""" def __init__(self, angle, velocity, height): """Create a projectile with given launch angle, initial velocity and height.""" self.xpos = 0.0 self.ypos = height theta = pi * angle / 180.0 self.xvel = velocity * cos(theta) self.yvel = velocity * sin(theta) Python Programming, 2/e
Module Documentation def update(self, time): """Update the state of this projectile to move it time seconds farther into its flight""" self.xpos = self.xpos + time * self.xvel yvel1 = self.yvel - 9.8 * time self.ypos = self.ypos + time * (self.yvel + yvel1) / 2.0 self.yvel = yvel1 def getY(self): "Returns the y position (height) of this projectile." return self.ypos def getX(self): "Returns the x position (distance) of this projectile." return self.xpos Python Programming, 2/e
Working with Multiple Modules Our main program can import from the projectile module in order to solve the original problem! # cball4.py # Simulation of the flight of a cannon ball (or other projectile) # This version uses a separate projectile module file from projectile import Projectile def getInputs(): a = eval(input("Enter the launch angle (in degrees): ")) v = eval(input("Enter the initial velocity (in meters/sec): ")) h = eval(input("Enter the initial height (in meters): ")) t = eval(input("Enter the time interval between position calculations: ")) return a,v,h,t def main(): angle, vel, h0, time = getInputs() cball = Projectile(angle, vel, h0) while cball.getY() >= 0: cball.update(time) print("\nDistance traveled: {0:0.1f} meters.".format(cball.getX()) Python Programming, 2/e
Working with Multiple Modules If you are testing a multi-module Python program, you need to be aware that reloading a module may not behave as you expect. When Python first imports a given module, it creates a module object that contains all the things defined in the module (a namespace). If a module imports successfully (no syntax errors), subsequent imports do not reload the module. Even if the source code for the module has been changed, re-importing it into an interactive session will not load the updated version. Python Programming, 2/e
Working with Multiple Modules The easiest way – start a new interactive session for testing whenever any of the modules involved in your testing are modified. This way you’re guaranteed to get a more recent import of all the modules you’re using. Python Programming, 2/e
Widgets One very common use of objects is in the design of graphical user interfaces (GUIs). Back in chapter 5 we talked about GUIs being composed of visual interface objects known as widgets. The Entry object defined in our graphics library is one example of a widget. Python Programming, 2/e
Example Program: Dice Roller Let’s build a couple useful widgets! Consider a program that rolls a pair of six-sided dice. The program will display the dice graphically and provide two buttons, one for rolling the dice and one for quitting the program. Python Programming, 2/e
Example Program: Dice Roller There are two kinds of widgets: buttons and dice. The two buttons will be examples of the Button class, while the dice images will be provided by dieView. Python Programming, 2/e
Building Buttons Most modern GUIs have buttons with 3-dimensional look and feel. Our simple graphics package does not have the machinery to produce buttons that appear to depress as they are clicked. All we can do is report back where the mouse was clicked after the click has been completed. Python Programming, 2/e
Building Buttons Our buttons will be rectangular regions in a graphics window where user clicks can influence the behavior of the running application. We need a way to determine whether a button has been clicked. It would be nice to be able to activate and deactivate (gray-out) individual buttons. Python Programming, 2/e
Building Buttons Constructor – Create a button in a window. We will specify the window, location/size of the button, and the label on the button. Activate – Set the state of the button to active. Deactivate – Set the state of the button to inactive. Python Programming, 2/e
Building Buttons Clicked– Indicate if the button was clicked. If the button is active, this method will determine if the point clicked is inside the button region. The point will have to be sent as a parameter to the method. getLabel– Returns the label string of a button. This is provided so that we can identify a particular button. Python Programming, 2/e
Building Buttons To support these operations, our buttons will need a number of instance variables. For example, buttons are drawn as a rectangle with some text centered on it. Invoking the activate and deactivate methods will change the appearance of the buttons. Python Programming, 2/e
Building Buttons Saving the Rectangle and Text objects as instance variables means we will be able to control the width of the outline and color of the label. Let’s try writing these methods and build up a list of possible instance variables! Once we have the list, we can write the constructor to initialize them. Python Programming, 2/e
Building Buttons In activate, we can signal a button is active by making its outline thicker and making the label text black. def activate(self): "Sets this button to 'active'. " self.label.setFill('black') self.rect.setWidth(2) self.active = True Remember, self refers to the button object. Our constructor will have to initialize self.label as an appropriate Text object and self.rect as a rectangle object. Self.active also has a Boolean instance variable to remember whether or not the button is currently inactive. Python Programming, 2/e
Building Buttons The code for deactivate is very similar: def deactivate(self): "Sets this button to 'inactive'." self.label.setFill('darkgrey') self.rect.setWidth(1) self.active = 0 Python Programming, 2/e
Building Buttons Let’s work on the clicked method. The graphics package has the getMouse method to see if and where the mouse has been clicked. If an application needs to get a button click, it will have to first call getMouse and then see which button, if any, the point is inside of. Python Programming, 2/e
Building Buttons pt = win.getMouse() if button1.clicked(pt): # Do button1 stuff elif button2.clicked(pt): # Do button2 stuff elif button3.clicked(pt): # Do button3 stuff … The main job of the clicked method is to determine whether a given point is inside the rectangular button. Python Programming, 2/e
Building Buttons The point is inside the button if its x and y coordinates lie between the extreme x and y values of the rectangle. This would be easiest if the button object had the min and max values of x and y as instance variables. Python Programming, 2/e
Building Buttons def clicked(self, p): "RETURNS true if button active and p is inside“ return self.active and \ self.xmin <= p.getX() <= self.xmax and \ self.ymin <= p.getY() <= self.ymax For this function to return True, all three parts of the Boolean expression must be true. The first part ensures that only active buttons will return that they have been clicked. The second and third parts ensure that the x and y values of the point that was clicked fall between the boundaries of the rectangle. Python Programming, 2/e
Building Buttons The only part that is left is to write the constructor: def __init__(self, win, center, width, height, label): """ Creates a rectangular button, eg: qb = Button(myWin, Point(30,25), 20, 10, 'Quit') """ w,h = width/2.0, height/2.0 x,y = center.getX(), center.getY() self.xmax, self.xmin = x+w, x-w self.ymax, self.ymin = y+h, y-h p1 = Point(self.xmin, self.ymin) p2 = Point(self.xmax, self.ymax) self.rect = Rectangle(p1,p2) self.rect.setFill('lightgray') self.rect.draw(win) self.label = Text(center, label) self.label.draw(win) self.deactivate() Buttons are positioned by providing a center point, width, and height. Python Programming, 2/e
Building Dice The purpose of the DieView class is to graphically display the value of a die. The face of the die is a square/rectangle, and the pips/spots on the die are circles. As before, the DieView class will have a constructor and a method. Python Programming, 2/e
Building Dice constructor – Create a die in a window. We will specify the window, the center point of the die, and the size of the die as parameters. setValue – Change the view to show a given value. The value to display will be passed as a parameter. Python Programming, 2/e
Building Dice Clearly, the hardest part of this will be to turn on the pips on the die to represent the current value of the die. One approach is to pre-place the pips, and make them the same color as the die. When the spot is turned on, it will be redrawn with a darker color. Python Programming, 2/e
Building Dice A standard die will need seven pips -- a column of three on the left and right sides, and one in the center. The constructor will create the background square and the seven circles. setValue will set the colors of the circles based on the value of the die. Python Programming, 2/e
Building Dice Python Programming, 2/e # dieview.py # A widget for displaying the value of a die from graphics import * class DieView: """ DieView is a widget that displays a graphical representation of a standard six-sided die.""" def __init__(self, win, center, size): """Create a view of a die, e.g.: d1 = GDie(myWin, Point(40,50), 20) creates a die centered at (40,50) having sides of length 20.""" # first defind some standard values self.win = win self.background = "white" # color of die face self.foreground = "black" # color of the pips self.psize = 0.1 * size # radius of each pip hsize = size / 2.0 # half of size offset = 0.6 * hsize # distance from center to outer pip Python Programming, 2/e
Building Dice # create a square for the face cx, cy = center.getX(), center.getY() p1 = Point(cx-hsize, cy-hsize) p2 = Point(cx+hsize, cy+hsize) rect = Rectangle(p1,p2) rect.draw(win) rect.setFill(self.background) # Create 7 circles for standard pip locations self.pip1 = self.__makePip(cx-offset, cy-offset) self.pip2 = self.__makePip(cx-offset, cy) self.pip3 = self.__makePip(cx-offset, cy+offset) self.pip4 = self.__makePip(cx, cy) self.pip5 = self.__makePip(cx+offset, cy-offset) self.pip6 = self.__makePip(cx+offset, cy) self.pip7 = self.__makePip(cx+offset, cy+offset) self.setValue(1) Python Programming, 2/e
Building Dice def __makePip(self, x, y): """Internal helper method to draw a pip at (x,y)""" pip = Circle(Point(x,y), self.psize) pip.setFill(self.background) pip.setOutline(self.background) pip.draw(self.win) return pip def setValue(self, value): """ Set this die to display value.""" # turn all pips off self.pip1.setFill(self.background) self.pip2.setFill(self.background) self.pip3.setFill(self.background) self.pip4.setFill(self.background) self.pip5.setFill(self.background) self.pip6.setFill(self.background) self.pip7.setFill(self.background) Python Programming, 2/e
Building Dice Python Programming, 2/e # turn correct pips on if value == 1: self.pip4.setFill(self.foreground) elif value == 2: self.pip1.setFill(self.foreground) self.pip7.setFill(self.foreground) elif value == 3: elif value == 4: self.pip3.setFill(self.foreground) self.pip5.setFill(self.foreground) elif value == 5: else: self.pip2.setFill(self.foreground) self.pip6.setFill(self.foreground) Python Programming, 2/e
Building Dice Things to notice: The size of the spots being 1/10 of the size of the die was determined by trial and error. We define and calculate various attributes of the die in the constructor and then use them in other methods and functions within the class so that if we wanted to change the appearance, all those values and the code to go with them is in one place, rather than throughout the class. Python Programming, 2/e
Building Dice __makePip is a helper function to draw each of the seven pips on the die. Since it is only useful within DieView, it’s appropriate to make it a class method. It’s name starts with __ to indicate that its use is “private” to the class and is not intended to be used outside the class. Python Programming, 2/e
The Main Program Python Programming, 2/e # roller.py # Graphics program to roll a pair of dice. Uses custom widgets # Button and GDie. from random import randrange from graphics import GraphWin, Point from button import Button from dieview import DieView def main(): # create the application window win = GraphWin("Dice Roller") win.setCoords(0, 0, 10, 10) win.setBackground("green2") # Draw the interface widgets die1 = DieView(win, Point(3,7), 2) die2 = DieView(win, Point(7,7), 2) rollButton = Button(win, Point(5,4.5), 6, 1, "Roll Dice") rollButton.activate() quitButton = Button(win, Point(5,1), 2, 1, "Quit") Python Programming, 2/e
The Main Program Python Programming, 2/e # Event loop pt = win.getMouse() while not quitButton.clicked(pt): if rollButton.clicked(pt): value1 = randrange(1,7) die1.setValue(value1) value2 = randrange(1,7) die2.setValue(value2) quitButton.activate() # close up shop win.close() main() Python Programming, 2/e
The Main Program The visual interface is built by creating the two DieViews and two Buttons. The roll button is initially active, but the quit button is deactivated. This forces the user to roll the dice at least once. The event loop is a sentinel loop that gets mouse clicks and processes them until the user clicks on the quit button. Python Programming, 2/e
The Main Program The if within the loop ensures that the dice are rolled only when the user clicks the roll button. Clicking a point that is not inside any button causes the loop to iterate without doing anything. Python Programming, 2/e
Python Programing: An Introduction to Computer Science Chapter 11 Data Collections Python Programming, 2/e
Objectives To understand the use of lists (arrays) to represent a collection of related data. To be familiar with the functions and methods available for manipulating Python lists. To be able to write programs that use lists to manage a collection of information. Python Programming, 2/e
Objectives To be able to write programs that use lists and classes to structure complex data. To understand the use of Python dictionaries for storing nonsequential collections. Python Programming, 2/e
Example Problem: Simple Statistics Many programs deal with large collections of similar information. Words in a document Students in a course Data from an experiment Customers of a business Graphics objects drawn on the screen Cards in a deck Python Programming, 2/e
Sample Problem: Simple Statistics Let’s review some code we wrote in chapter 8: # average4.py # A program to average a set of numbers # Illustrates sentinel loop using empty string as sentinel def main(): sum = 0.0 count = 0 xStr = input("Enter a number (<Enter> to quit) >> ") while xStr != "": x = eval(xStr) sum = sum + x count = count + 1 print("\nThe average of the numbers is", sum / count) main() Python Programming, 2/e Python Programming, 1/e
Sample Problem: Simple Statistics This program allows the user to enter a sequence of numbers, but the program itself doesn’t keep track of the numbers that were entered – it only keeps a running total. Suppose we want to extend the program to compute not only the mean, but also the median and standard deviation. Python Programming, 2/e
Sample Problem: Simple Statistics The median is the data value that splits the data into equal-sized parts. For the data 2, 4, 6, 9, 13, the median is 6, since there are two values greater than 6 and two values that are smaller. One way to determine the median is to store all the numbers, sort them, and identify the middle value. Python Programming, 2/e
Sample Problem: Simple Statistics The standard deviation is a measure of how spread out the data is relative to the mean. If the data is tightly clustered around the mean, then the standard deviation is small. If the data is more spread out, the standard deviation is larger. The standard deviation is a yardstick to measure/express how exceptional the data is. Python Programming, 2/e
Sample Problem: Simple Statistics The standard deviation is Here is the mean, represents the ith data value and n is the number of data values. The expression is the square of the “deviation” of an individual item from the mean. Python Programming, 2/e
Sample Problem: Simple Statistics The numerator is the sum of these squared “deviations” across all the data. Suppose our data was 2, 4, 6, 9, and 13. The mean is 6.8 The numerator of the standard deviation is Python Programming, 2/e
Sample Problem: Simple Statistics As you can see, calculating the standard deviation not only requires the mean (which can’t be calculated until all the data is entered), but also each individual data element! We need some way to remember these values as they are entered. Python Programming, 2/e
Applying Lists We need a way to store and manipulate an entire collection of numbers. We can’t just use a bunch of variables, because we don’t know many numbers there will be. What do we need? Some way of combining an entire collection of values into one object. Python Programming, 2/e
Lists and Arrays Python lists are ordered sequences of items. For instance, a sequence of n numbers might be called S: S = s0, s1, s2, s3, …, sn-1 Specific values in the sequence can be referenced using subscripts. By using numbers as subscripts, mathematicians can succinctly summarize computations over items in a sequence using subscript variables. Python Programming, 2/e
Lists and Arrays Suppose the sequence is stored in a variable s. We could write a loop to calculate the sum of the items in the sequence like this: sum = 0 for i in range(n): sum = sum + s[i] Almost all computer languages have a sequence structure like this, sometimes called an array. Python Programming, 2/e
Lists and Arrays A list or array is a sequence of items where the entire sequence is referred to by a single name (i.e. s) and individual items can be selected by indexing (i.e. s[i]). In other programming languages, arrays are generally a fixed size, meaning that when you create the array, you have to specify how many items it can hold. Arrays are generally also homogeneous, meaning they can hold only one data type. Python Programming, 2/e
Lists and Arrays Python lists are dynamic. They can grow and shrink on demand. Python lists are also heterogeneous, a single list can hold arbitrary data types. Python lists are mutable sequences of arbitrary objects. Python Programming, 2/e
List Operations Operator Meaning <seq> + <seq> Concatenation <seq> * <int-expr> Repetition <seq>[] Indexing len(<seq>) Length <seq>[:] Slicing for <var> in <seq>: Iteration <expr> in <seq> Membership (Boolean) Python Programming, 2/e
List Operations Except for the membership check, we’ve used these operations before on strings. The membership operation can be used to see if a certain value appears anywhere in a sequence. >>> lst = [1,2,3,4] >>> 3 in lst True Python Programming, 2/e
List Operations The summing example from earlier can be written like this: sum = 0 for x in s: sum = sum + x Unlike strings, lists are mutable: >>> lst = [1,2,3,4] >>> lst[3] 4 >>> lst[3] = "Hello“ >>> lst [1, 2, 3, 'Hello'] >>> lst[2] = 7 >>> lst [1, 2, 7, 'Hello'] Python Programming, 2/e
List Operations A list of identical items can be created using the repetition operator. This command produces a list containing 50 zeroes: zeroes = [0] * 50 Python Programming, 2/e
List Operations Lists are often built up one piece at a time using append. nums = [] x = eval(input('Enter a number: ')) while x >= 0: nums.append(x) x = eval(input('Enter a number: ')) Here, nums is being used as an accumulator, starting out empty, and each time through the loop a new value is tacked on. Python Programming, 2/e
List Operations Method Meaning <list>.append(x) Add element x to end of list. <list>.sort() Sort (order) the list. A comparison function may be passed as a parameter. <list>.reverse() Reverse the list. <list>.index(x) Returns index of first occurrence of x. <list>.insert(i, x) Insert x into list at index i. <list>.count(x) Returns the number of occurrences of x in list. <list>.remove(x) Deletes the first occurrence of x in list. <list>.pop(i) Deletes the ith element of the list and returns its value. Python Programming, 2/e
List Operations Python Programming, 2/e >>> lst = [3, 1, 4, 1, 5, 9] >>> lst.append(2) >>> lst [3, 1, 4, 1, 5, 9, 2] >>> lst.sort() [1, 1, 2, 3, 4, 5, 9] >>> lst.reverse() [9, 5, 4, 3, 2, 1, 1] >>> lst.index(4) 2 >>> lst.insert(4, "Hello") [9, 5, 4, 3, 'Hello', 2, 1, 1] >>> lst.count(1)s >>> lst.remove(1) [9, 5, 4, 3, 'Hello', 2, 1] >>> lst.pop(3) 3 [9, 5, 4, 'Hello', 2, 1] Python Programming, 2/e
List Operations Most of these methods don’t return a value – they change the contents of the list in some way. Lists can grow by appending new items, and shrink when items are deleted. Individual items or entire slices can be removed from a list using the del operator. Python Programming, 2/e
List Operations >>> myList=[34, 26, 0, 10] >>> del myList[1] >>> myList [34, 0, 10] >>> del myList[1:3] >>> myList [34] del isn’t a list method, but a built-in operation that can be used on list items. Python Programming, 2/e
List Operations Basic list principles A list is a sequence of items stored as a single object. Items in a list can be accessed by indexing, and sublists can be accessed by slicing. Lists are mutable; individual items or entire slices can be replaced through assignment statements. Python Programming, 2/e
List Operations Lists support a number of convenient and frequently used methods. Lists will grow and shrink as needed. Python Programming, 2/e
Statistics with Lists One way we can solve our statistics problem is to store the data in lists. We could then write a series of functions that take a list of numbers and calculates the mean, standard deviation, and median. Let’s rewrite our earlier program to use lists to find the mean. Python Programming, 2/e
Statistics with Lists Let’s write a function called getNumbers that gets numbers from the user. We’ll implement the sentinel loop to get the numbers. An initially empty list is used as an accumulator to collect the numbers. The list is returned once all values have been entered. Python Programming, 2/e
Statistics with Lists def getNumbers(): nums = [] # start with an empty list # sentinel loop to get numbers xStr = input("Enter a number (<Enter> to quit) >> ") while xStr != "": x = eval(xStr) nums.append(x) # add this value to the list return nums Using this code, we can get a list of numbers from the user with a single line of code: data = getNumbers() Python Programming, 2/e
Statistics with Lists Now we need a function that will calculate the mean of the numbers in a list. Input: a list of numbers Output: the mean of the input list def mean(nums): sum = 0.0 for num in nums: sum = sum + num return sum / len(nums) Python Programming, 2/e
Statistics with Lists The next function to tackle is the standard deviation. In order to determine the standard deviation, we need to know the mean. Should we recalculate the mean inside of stdDev? Should the mean be passed as a parameter to stdDev? Python Programming, 2/e
Statistics with Lists Recalculating the mean inside of stdDev is inefficient if the data set is large. Since our program is outputting both the mean and the standard deviation, let’s compute the mean and pass it to stdDev as a parameter. Python Programming, 2/e
Statistics with Lists def stdDev(nums, xbar): sumDevSq = 0.0 for num in nums: dev = xbar - num sumDevSq = sumDevSq + dev * dev return sqrt(sumDevSq/(len(nums)-1)) The summation from the formula is accomplished with a loop and accumulator. sumDevSq stores the running sum of the squares of the deviations. Python Programming, 2/e
Statistics with Lists We don’t have a formula to calculate the median. We’ll need to come up with an algorithm to pick out the middle value. First, we need to arrange the numbers in ascending order. Second, the middle value in the list is the median. If the list has an even length, the median is the average of the middle two values. Python Programming, 2/e
Statistics with Lists Pseudocode - sort the numbers into ascending order if the size of the data is odd: median = the middle value else: median = the average of the two middle values return median Python Programming, 2/e
Statistics with Lists def median(nums): nums.sort() size = len(nums) midPos = size // 2 if size % 2 == 0: median = (nums[midPos] + nums[midPos-1]) / 2 else: median = nums[midPos] return median Python Programming, 2/e
Statistics with Lists With these functions, the main program is pretty simple! def main(): print("This program computes mean, median and standard deviation.") data = getNumbers() xbar = mean(data) std = stdDev(data, xbar) med = median(data) print("\nThe mean is", xbar) print("The standard deviation is", std) print("The median is", med) Python Programming, 2/e
Statistics with Lists Statistical analysis routines might come in handy some time, so let’s add the capability to use this code as a module by adding: if __name__ == '__main__': main() Python Programming, 2/e
Lists of Objects All of the list examples we’ve looked at so far have involved simple data types like numbers and strings. We can also use lists to store more complex data types, like our student information from chapter ten. Python Programming, 2/e
Lists of Objects Our grade processing program read through a file of student grade information and then printed out information about the student with the highest GPA. A common operation on data like this is to sort it, perhaps alphabetically, perhaps by credit-hours, or even by GPA. Python Programming, 2/e
Lists of Objects Let’s write a program that sorts students according to GPA using our Sutdent class from the last chapter. Get the name of the input file from the user Read student information into a list Sort the list by GPA Get the name of the output file from the user Write the student information from the list into a file Python Programming, 2/e
Lists of Objects Let’s begin with the file processing. The following code reads through the data file and creates a list of students. def readStudents(filename): infile = open(filename, 'r') students = [] for line in infile: students.append(makeStudent(line)) infile.close() return students We’re using the makeStudent from the gpa program, so we’ll need to remember to import it. Python Programming, 2/e
Lists of Objects Let’s also write a function to write the list of students back to a file. Each line should contain three pieces of information, separated by tabs: name, credit hours, and quality points. def writeStudents(students, filename): # students is a list of Student objects outfile = open(filename, 'w') for s in students: print((s.getName(),s.getHours(),s.getQPoints(), sep="\t", file=outfile) outfile.close() Python Programming, 2/e
Lists of Objects Using the functions readStudents and writeStudents, we can convert our data file into a list of students and then write them back to a file. All we need to do now is sort the records by GPA. In the statistics program, we used the sort method to sort a list of numbers. How does Python sort lists of objects? Python Programming, 2/e
Lists of Objects To make sorting work with our objects, we need to tell sort how the objects should be compared. Can supply a function to produce the key for an object using <list>.sort(key=<somefunc>) To sort by GPA, we need a function that takes a Student as parameter and returns the student's GPA. Python Programming, 2/e
Lists of Objects def use_gpa(aStudent): return aStudent.gpa() We can now sort the data by calling sort with the key function as a keyword parameter. data.sort(key=use_gpa) Python Programming, 2/e
Lists of Objects data.sort(key=use_gpa) Notice that we didn’t put ()’s after the function name. This is because we don’t want to call use_gpa, but rather, we want to send use_gpa to the sort method. Python Programming, 2/e
Lists of Objects Actually, defining use_gpa was unnecessary. The gpa method in the Student class is a function that takes a student as a parameter (formally, self) and returns GPA. Can use it: data.sort(key=Student.gpa) Python Programming, 2/e
Lists of Objects Python Programming, 2/e def main(): # gpasort.py print ("This program sorts student grade information by GPA") filename = input("Enter the name of the data file: ") data = readStudents(filename) data.sort(Student.gpa) filename = input("Enter a name for the output file: ") writeStudents(data, filename) print("The data has been written to", filename) if __name__ == '__main__': main() # gpasort.py # A program to sort student information into GPA order. from gpa import Student, makeStudent def readStudents(filename): infile = open(filename, 'r') students = [] for line in infile: students.append(makeStudent(line)) infile.close() return students def writeStudents(students, filename): outfile = open(filename, 'w') for s in students: print(s.getName(), s.getHours(), s.getQPoints(), sep="\t", file=outfile) outfile.close() Python Programming, 2/e
Designing with Lists and Classes In the dieView class from chapter ten, each object keeps track of seven circles representing the position of pips on the face of the die. Previously, we used specific instance variables to keep track of each, pip1, pip2, pip3, … Python Programming, 2/e
Designing with Lists and Classes What happens if we try to store the circle objects using a list? In the previous program, the pips were created like this: self.pip1 = self.__makePip(cx, cy) __makePip is a local method of the DieView class that creates a circle centered at the position given by its parameters. Python Programming, 2/e
Designing with Lists and Classes One approach is to start with an empty list of pips and build up the list one pip at a time. pips = [] pips.append(self.__makePip(cx-offset,cy-offset) pips.append(self.__makePip(cx-offset,cy) … self.pips = pips Python Programming, 2/e
Designing with Lists and Classes An even more straightforward approach is to create the list directly. self.pips = [self.__makePip(cx-offset,cy-offset), self.__makePip(cx-offset,cy), … self.__makePip(cx+offset,cy+offset) ] Python is smart enough to know that this object is continued over a number of lines, and waits for the ‘]’. Listing objects like this, one per line, makes it much easier to read. Python Programming, 2/e
Designing with Lists and Classes Putting our pips into a list makes many actions simpler to perform. To blank out the die by setting all the pips to the background color: for pip in self.pips: pip.setFill(self.background) This cut our previous code from seven lines to two! Python Programming, 2/e
Designing with Lists and Classes We can turn the pips back on using the pips list. Our original code looked like this: self.pip1.setFill(self.foreground) self.pip4.setFill(self.foreground) self.pip7.setFill(self.foreground) Into this: self.pips[0].setFill(self.foreground) self.pips[3].setFill(self.foreground) self.pips[6].setFill(self.foreground) Python Programming, 2/e
Designing with Lists and Classes Here’s an even easier way to access the same methods: for i in [0,3,6]: self.pips[i].setFill(self.foreground) We can take advantage of this approach by keeping a list of which pips to activate! Loop through pips and turn them all off Determine the list of pip indexes to turn on Loop through the list of indexes - turn on those pips Python Programming, 2/e
Designing with Lists and Classes for pip in self.pips: self.pip.setFill(self.background) if value == 1: on = [3] elif value == 2: on = [0,6] elif value == 3: on = [0,3,6] elif value == 4: on = [0,2,4,6] elif value == 5: on = [0,2,3,4,6] else: on = [0,1,2,3,4,5,6] for i in on: self.pips[i].setFill(self.foreground) Python Programming, 2/e
Designing with Lists and Classes We can do even better! The correct set of pips is determined by value. We can make this process table-driven instead. We can use a list where each item on the list is itself a list of pip indexes. For example, the item in position 3 should be the list [0,3,6] since these are the pips that must be turned on to show a value of 3. Python Programming, 2/e
Designing with Lists and Classes Here’s the table-driven code: onTable = [ [], [3], [2,4], [2,3,4], [0,2,4,6], [0,2,3,4,6], [0,1,2,4,5,6] ] for pip in self.pips: self.pip.setFill(self.background) on = onTable[value] for i in on: self.pips[i].setFill(self.foreground) Python Programming, 2/e
Designing with Lists and Classes onTable = [ [], [3], [2,4], [2,3,4], [0,2,4,6], [0,2,3,4,6], [0,1,2,4,5,6] ] for pip in self.pips: self.pip.setFill(self.background) on = onTable[value] for i in on: self.pips[i].setFill(self.foreground) The table is padded with ‘[]’ in the 0 position, since it shouldn’t ever be used. The onTable will remain unchanged through the life of a dieView, so it would make sense to store this table in the constructor and save it in an instance variable. Python Programming, 2/e
Designing with Lists and Classes # dieview2.py # A widget for displaying the value of a die. # This version uses lists to simplify keeping track of pips. class DieView: """ DieView is a widget that displays a graphical representation of a standard six-sided die.""" def __init__(self, win, center, size): """Create a view of a die, e.g.: d1 = GDie(myWin, Point(40,50), 20) creates a die centered at (40,50) having sides of length 20.""" # first define some standard values self.win = win self.background = "white" # color of die face self.foreground = "black" # color of the pips self.psize = 0.1 * size # radius of each pip hsize = size / 2.0 # half of size offset = 0.6 * hsize # distance from center to outer pips # create a square for the face cx, cy = center.getX(), center.getY() p1 = Point(cx-hsize, cy-hsize) p2 = Point(cx+hsize, cy+hsize) rect = Rectangle(p1,p2) rect.draw(win) rect.setFill(self.background) # Create 7 circles for standard pip locations self.pips = [ self.__makePip(cx-offset, cy-offset), self.__makePip(cx-offset, cy), self.__makePip(cx-offset, cy+offset), self.__makePip(cx, cy), self.__makePip(cx+offset, cy-offset), self.__makePip(cx+offset, cy), self.__makePip(cx+offset, cy+offset) ] # Create a table for which pips are on for each value self.onTable = [ [], [3], [2,4], [2,3,4], [0,2,4,6], [0,2,3,4,6], [0,1,2,4,5,6] ] self.setValue(1) def __makePip(self, x, y): """Internal helper method to draw a pip at (x,y)""" pip = Circle(Point(x,y), self.psize) pip.setFill(self.background) pip.setOutline(self.background) pip.draw(self.win) return pip def setValue(self, value): """ Set this die to display value.""" # Turn all the pips off for pip in self.pips: # Turn the appropriate pips back on for i in self.onTable[value]: self.pips[i].setFill(self.foreground) Python Programming, 2/e
Designing with Lists and Classes Lastly, this example showcases the advantages of encapsulation. We have improved the implementation of the dieView class, but we have not changed the set of methods it supports. We can substitute this new version of the class without having to modify any other code! Encapsulation allows us to build complex software systems as a set of “pluggable modules.” Python Programming, 2/e
Case Study: Python Calculator The new dieView class shows how lists can be used effectively as instance variables of objects. Our pips list and onTable contain circles and lists, respectively, which are themselves objects. We can view a program itself as a collection of data structures (collections and objects) and a set of algorithms that operate on those data structures. Python Programming, 2/e
A Calculator as an Object Let’s develop a program that implements a Python calculator. Our calculator will have buttons for The ten digits (0-9) A decimal point (.) Four operations (+,-,*,/) A few special keys ‘C’ to clear the display ‘<-’ to backspace in the display ‘=’ to do the calculation Python Programming, 2/e
A Calculator as an Object Python Programming, 2/e
A Calculator as an Object We can take a simple approach to performing the calculations. As buttons are pressed, they show up in the display, and are evaluated and displayed when the = is pressed. We can divide the functioning of the calculator into two parts: creating the interface and interacting with the user. Python Programming, 2/e
Constructing the Interface First, we create a graphics window. The coordinates were chosen to simplify the layout of the buttons. In the last line, the window object is stored in an instance variable so that other methods can refer to it. def __init__(self): # create the window for the calculator win = GraphWin("calculator") win.setCoords(0,0,6,7) win.setBackground("slategray") self.win = win Python Programming, 2/e
Constructing the Interface Our next step is to create the buttons, reusing the button class. # create list of buttons # start with all the standard sized buttons # bSpecs gives center coords and label of buttons bSpecs = [(2,1,'0'), (3,1,'.'), (1,2,'1'), (2,2,'2'), (3,2,'3'), (4,2,'+'), (5,2,'-'), (1,3,'4'), (2,3,'5'), (3,3,'6'), (4,3,'*'), (5,3,'/'), (1,4,'7'), (2,4,'8'), (3,4,'9'), (4,4,'<-'),(5,4,'C')] self.buttons = [] for cx,cy,label in bSpecs: self.buttons.append(Button(self.win,Point(cx,cy),.75,.75,label)) # create the larger = button self.buttons.append(Button(self.win, Point(4.5,1), 1.75, .75, "=")) # activate all buttons for b in self.buttons: b.activate() bspecs contains a list of button specifications, including the center point of the button and its label. Python Programming, 2/e
Constructing the Interface Each specification is a tuple. A tuple looks like a list but uses ‘()’ rather than ‘[]’. Tuples are sequences that are immutable. Python Programming, 2/e
Constructing the Interface Conceptually, each iteration of the loop starts with an assignment: (cx,cy,label)=<next item from bSpecs> Each item in bSpecs is also a tuple. When a tuple of variables is used on the left side of an assignment, the corresponding components of the tuple on the right side are unpacked into the variables on the left side. The first time through it’s as if we had: cx,cy,label = 2,1,”0” Python Programming, 2/e
Constructing the Interface Each time through the loop, another tuple from bSpecs is unpacked into the variables in the loop heading. These values are then used to create a Button that is appended to the list of buttons. Creating the display is simple – it’s just a rectangle with some text centered on it. We need to save the text object as an instance variable so its contents can be accessed and changed. Python Programming, 2/e
Constructing the Interface Here’s the code to create the display bg = Rectangle(Point(.5,5.5), Point(5.5,6.5)) bg.setFill('white') bg.draw(self.win) text = Text(Point(3,6), "") text.draw(self.win) text.setFace("courier") text.setStyle("bold") text.setSize(16) self.display = text Python Programming, 2/e
Processing Buttons Now that the interface is drawn, we need a method to get it running. We’ll use an event loop that waits for a button to be clicked and then processes that button. def run(self): # Infinite 'event loop' to process button clicks. while True: key = self.getButton() self.processButton(key) Python Programming, 2/e
Processing Buttons We continue getting mouse clicks until a button is clicked. To determine whether a button has been clicked, we loop through the list of buttons and check each one. def getButton(self): # Waits for a button to be clicked and # returns the label of # the button that was clicked. while True: p = self.win.getMouse() for b in self.buttons: if b.clicked(p): return b.getLabel() # method exit Python Programming, 2/e
Processing Buttons Having the buttons in a list like this is a big win. A for loop is used to look at each button in turn. If the clicked point p turns out to be in one of the buttons, the label of the button is returned, providing an exit from the otherwise infinite loop. Python Programming, 2/e
Processing Buttons The last step is to update the display of the calculator according to which button was clicked. A digit or operator is appended to the display. If key contains the label of the button, and text contains the current contents of the display, the code is: self.display.setText(text+key) Python Programming, 2/e
Processing Buttons The clear key blanks the display: self.display.setText("") The backspace key strips off one character: self.display.setText(text[:-1]) The equal key causes the expression to be evaluated and the result displayed. Python Programming, 2/e
Processing Buttons try: result = eval(text) except: result = 'ERROR' self.display.setText(str(result)) Exception handling is necessary here to catch run-time errors if the expression being evaluated isn’t a legal Python expression. If there’s an error, the program will display ERROR rather than crash. Python Programming, 2/e
Python Programming: An Introduction To Computer Science Chapter 12 Object-Oriented Design Python Programming, 2/e Python Programming, 2/e
Objectives To understand the process of object-oriented design. To be able to read and understand object-oriented programs. To understand the concepts of encapsulation, polymorphism and inheritance as they pertain to object-oriented design and programming. Python Programming, 2/e
Objectives To be able to design moderately complex software using object-oriented design. Python Programming, 2/e
The Process of OOD Most modern computer applications are designed using a data-centered view of computing called object-oriented design (OOD). The essence of OOD is describing a system in terms of magical black boxes and their interfaces. Python Programming, 2/e
The Process of OOD Each component provides a service or set of services through its interface. Other components are users or clients of the services. A client only needs to understand the interface of a service – implementation details are not important, they may be changed and shouldn’t affect the client at all! Python Programming, 2/e
The Process of OOD The component providing the service shouldn’t have to consider how the service is used – it just needs to provide the service “as advertised” via the interface. This separation of concerns makes the design of complex systems possible. Python Programming, 2/e
The Process of OOD In top-down design, functions serve the role of the black box. Client programs can use the functions as long as it understands what the function does. How the function accomplishes its task is encapsulated within the function. Python Programming, 2/e
The Process of OOD In OOD, the black boxes are objects. The magic behind the objects is in the class definitions. Once a class definition is written, we can ignore how the class works and rely on the external interface, its methods. You’ve seen this when using the graphics library – you were able to draw a circle without having to know all the nitty-gritty details encapsulated in class definitions for GraphWin and Circle. Python Programming, 2/e
The Process of OOD Breaking a large problem into a set of cooperating classes reduces the complexity that must be considered to understand any given part of the program. Each class stands on its own! OOD is the process of finding and defining a useful set of classes for a given problem. Like design, it’s part art and part science. The more you design, the better you’ll get. Python Programming, 2/e
The Process of OOD Here are some guidelines for OOD: Look for object candidates The goal is to define a set of objects that will be helpful in solving the problem. Start with a careful consideration of the problem statement – objects are usually described by nouns. Which nouns in your problem statement would be represented in your program? Which have interesting behavior or properties? Python Programming, 2/e
The Process of OOD Look for object candidates Things that can be represented as primitive data types (numbers or strings) are probably not important object candidates. Things to look for: a grouping of related data items (e.g., point coordinates, employee data) Identify instance variables Once you think of some possible objects, think of the kinds of information each object will need to do its job. Python Programming, 2/e
The Process of OOD Identify instance variables Think about interfaces Some object attributes will have primitive data types, while others may be complex types that suggest other useful objects/classes. Strive to find good “home” classes for all the data in your program. Think about interfaces What operations would be required for objects of that class to be useful? Consider the verbs in the problem statement. Python Programming, 2/e
The Process of OOD Think about interfaces Verbs describe actions. List the methods that the class will require. Remember – all of the manipulation of the object’s data should be done through the methods you provide. Refine the nontrivial methods Some methods will probably look like they can be accomplished in a few lines of code, while others may take more programming effort. Python Programming, 2/e
The Process of OOD Refine the nontrivial methods Use top-down design and stepwise refinement to flesh out the details of the more difficult methods. As you’re programming, you may discover that some new interactions with other classes are needed, and you may need to add new methods to other classes. Sometimes you may discover a need for a brand-new kind of object that calls for the definition of another class. Python Programming, 2/e
The Process of OOD Design iteratively It’s not unusual to bounce back and forth between designing new classes and adding methods to existing classes. Work on whatever is demanding your attention. No one designs a program top to bottom in a linear, systematic fashion. Make progress wherever progress needs to be made. Python Programming, 2/e
The Process of OOD Try out alternatives Don’t be afraid to scrap an approach that doesn’t seem to be working, or to follow an idea and see where it leads. Good design involves a lot of trial and error! When you look at the programs of others, you are looking at finished work, not the process used to get there. Well-designed programs are probably not the result of a first try. As Fred Brooks said, “Plan to throw one away.” Python Programming, 2/e
The Process of OOD Keep it simple At each step in the design, try to find the simplest approach that will solve the problem. Don’t design in extra complexity until it is clear that a more complex approach is needed. Python Programming, 2/e
Case Study: Racquetball Simulation You may want to review our top-down design of the racquetball simulation from Chapter 9. We want to simulate multiple games of racquetball where the ability of the two opponents is represented by the probability that they win a point when they are serving. Python Programming, 2/e
Case Study: Racquetball Simulation Inputs: Probability for player A Probability for player B The number of games to simulate Output: A nicely formatted summary of the results Python Programming, 2/e
Case Study: Racquetball Simulation Previously, we ended a game when one of the players reached 15 points. This time, let’s also consider shutouts. If one player gets to 7 points before the other player has scored a point, the game ends. The simulation should keep track of each players’ wins and the number of wins that are shutouts. Python Programming, 2/e
Candidate Objects and Methods Our first task – find a set of objects that could be useful in solving this problem. Problem statement – “Simulate a series of racquetball games between two players and record some statistics about the series of games.” This suggests two things Simulate a game Keep track of some statistics Python Programming, 2/e
Candidate Objects and Methods First, let’s simulate the game. Use an object to represent a single game of racquetball. This game will have to keep track of some information, namely, the skill levels of the two players. Let’s call this class RBallGame. Its constructor requires parameters for the probabilities of the two players. Python Programming, 2/e
Candidate Objects and Methods What else do we need? We need to play the game. We can give the class a play method that simulates the game until it’s over. We could then create and play a racquetball game with two lines of code! theGame = RBallGame(probA, probB) theGame.play() Python Programming, 2/e
Candidate Objects and Methods To play several games, we just need to put a loop around this code. We’ll need four counts to keep track of at least four counts to print the results of our simulation: wins for A, wins for B, shutouts for A, and shutouts for B We could also count the number of games played, but we can calculate this from the counts above. Python Programming, 2/e
Candidate Objects and Methods These four related pieces of information could be grouped into a single object, which could be an instance of the class SimStats. A SimStats object will keep track of all the information about a series of games. Python Programming, 2/e
Candidate Objects and Methods What operations would be useful on these statistics? The constructor should initialize the counts to 0. We need a way to update these counts while the games are simulated. How can we do this? The easiest approach would be to send the entire game object to the method and let it extract the appropriate information. Once the games are done, we need a method to print out the results – printReport. Python Programming, 2/e
Candidate Objects and Methods def main(): printIntro() probA, probB, n = getInputs() # Play the games stats = SimStats() for i in range(n): theGame = RBallGame(probA, probB) # Create a new game theGame.play() # Play it stats.update(theGame) # Get info about completed game # Print the results stats.printReport() The helper functions that print an introduction and get inputs should be easy. Let’s work on the SimStats class! Python Programming, 2/e
Implementing SimStats The constructor for SimStats just needs to initialize the four counts to 0. class SimStats: def __init__(self): self.winA = 0 self.winB = 0 self.shutsA = 0 self.shutsB = 0 Python Programming, 2/e
Implementing SimStats The update method takes a game as a parameter and updates the four counts appropriately. The heading will look like this: def update(self, aGame): We need to know the final score of the game, be we can’t directly access that information since it is an instance variable of aGame. Python Programming, 2/e
Implementing SimStats We need a new method in RBallGame that will report the final score. Let’s call this new method getScores, and it will return the scores for player A and player B. Now the algorithm for update is straightforward. Python Programming, 2/e
Implementing SimStats def update(self, aGame): a, b = aGame.getScores() if a > b: # A won the game self.winsA = self.winsA + 1 if b == 0: self.shutsA = self.shutsA + 1 else: # B won the game self.winsB = self.winsB + 1 if a == 0: self.shutsB = self.shutsB + 1 Python Programming, 2/e
Implementing SimStats The only thing left is a method to print out the results. The method printReport will generate a table showing the wins win percentage shutouts and shutout percentage for each player. Python Programming, 2/e
Implementing SimStats Here’s sample output: Summary of 500 games: wins (% total) shutouts (% wins) -------------------------------------------- Player A: 393 78.6% 72 18.3% Player B: 107 21.4% 8 7.5% The headings are easy to handle, but printing the output in nice columns is harder. We also need to avoid division by 0 when calculating percentages. Python Programming, 2/e
Implementing SimStats Let’s move printing the lines of the table into the method printLine. The printLine method will need the player label (A or B), number of wins and shutouts, and the total number of games (for calculating percentages). Python Programming, 2/e
Implementing SimStats def printReport(self): # Print a nicely formatted report n = self.winsA + self.winsB print "Summary of", n , "games:" print print " wins (% total) shutouts (% wins) " print "--------------------------------------------" self.printLine("A", self.winsA, self.shutsA, n) self.printLine("B", self.winsB, self.shutsB, n) To finish the class, we will implement printLine. This method makes heavy use of string formatting. You may want to review string formatting in chapter ?? Python Programming, 2/e
Implementing SimStats def printLine(self, label, wins, shuts, n): template = "Player %s: %4d %5.1f%% %11d %s " if wins == 0: # Avoid division by zero! shutStr = "----- " else: shutStr = "%4.1f%%" % (float(shuts)/wins*100) print template % (label, wins, float(wins)/n*100,\ shuts, shutStr) We define a template for the information that will appear in each line. The if ensures we don’t divide by 0, and the template treats it as a string. Python Programming, 2/e
Implementing RBallGame This class needs a constructor that accepts two probabilities as parameters, a play method that plays the game, and a getScores method that reports the scores. Python Programming, 2/e
Implementing RBallGame What will a racquetball game need to know? To play the game, we need to know The probability for each player The score for each player Which player is serving The probability and score are more related to a particular player, while the server is a property of the game between the two players. Python Programming, 2/e
Implementing RBallGame So, a game needs to know who the players are The players themselves could be objects that know their probability and score and which is serving. If the players are objects, then we need a class to define their behavior. Let’s call it Player. Python Programming, 2/e
Implementing RBallGame The Player object will keep track of a player’s probability and score. When a Player is initialized, the probability will be passed as a parameter. Its score will be set to 0. Let’s develop Player as we work on RBallGame. Python Programming, 2/e
Implementing RBallGame The game will need instance variables for the two players, and another variable to keep track of which player has service. class RBallGame: def __init__(self, probA, probB): # Create a new game having players with the given probs. self.playerA = Player(probA) self.playerB = Player(probB) self.server = self.playerA # Player A always serves first Python Programming, 2/e
Implementing RBallGame Suppose we create an instance of RBallGame like this: theGame = RBallGame(.6, .5) Python Programming, 2/e
Implementing RBallGame Our next step is to code how to play the game! In chapter 9 we developed an algorithm that continues to serve rallies and awards points or changes service as appropriate until the game is over. Let’s translate this algorithm into our object-based code! Python Programming, 2/e
Implementing RBallGame Firstly, we need a loop that continues as long as the game is not over. The decision whether a game is over or not can only be done by looking at the game object itself. Let’s assume we have an isOver method which can be used. Python Programming, 2/e
Implementing RBallGame def play(self): # Play the game to completion while not self.isOver(): Within the loop, the serving player needs to serve, and, based on the result, we decide what to do. This suggests that the Player objects should have a method that performs a serve. Python Programming, 2/e
Implementing RBallGame Whether the serve is not depends on the probability stored within each player object, so, one can ask the server if the serve was won or lost! if self.server.winsServe(): Based on the result, a point is awarded or service changes. To award a point, the player’s score needs to be changed, which requires the player object to increment the score. Python Programming, 2/e
Implementing RBallGame Changing servers is done at the game level, since this information is kept in the server instance variable of RBallGame. Here’s the completed play method: Python Programming, 2/e
Implementing RBallGame def play(self): # Play the game to completion while not self.isOver(): if self.server.winsServe(): self.server.incScore() else: self.changeServer() Remember, self is an RBallGame! While this algorithm is simple, we need two more methods (isOver and changeServer) in the RBallGame class and two more (winServe and inScore) for the Player class. Python Programming, 2/e
Implementing RBallGame Before working on these methods, let’s go back and finish the other top-level method of the RBallGame class, getScores, which returns the scores of the two players. The player objects actually know the scores, so we need a method that asks a player to return its score. Python Programming, 2/e
Implementing RBallGame def getScores(self): # RETURNS the current scores of player A and player B return self.playerA.getScore(), self.playerB.getScore() This adds one more method to be implemented in the Player class! Don’t forget it!! To finish the RBallGame class, all that is needed is to write the isOver and changeServer methods (left as an exercise). Python Programming, 2/e
Implementing Player While developing the RBallGame class, we discovered the need for a Player class that encapsulates the service probability and current score for a player. The Player class needs a suitable constructor and methods for winsServe, incScore, and getScore. Python Programming, 2/e
Implementing Player In the class constructor, we need to initialize the instance variables. The probability will be passed as a variable, and the score is set to 0. def __init__(self, prob): # Create a player with this probability self.prob = prob self.score = 0 Python Programming, 2/e
Implementing Player To see if a player wins a serve, compare the probability of service win to a random number between 0 and 1. def winsServe(self): # RETURNS true with probability self.prob return random() <= self.prob Python Programming, 2/e
Implementing Player To give a player a point, we add one to the score. def incScore(self): # Add a point to this player's score self.score = self.score + 1 The final method returns the value of the score. def getScore(self): # RETURN this player's current score return self.score Python Programming, 2/e
Implementing Player You may think it’s silly to create a class with many one or two-line methods. This is quite common in well-modularized, object-oriented programs. If the pieces are so simple that their implementation is obvious, we have confidence that it must be right! Python Programming, 2/e
The Complete Program Python Programming, 2/e # objrrball.py # Simulation of a racquet game. # Illustrates design with objects. from random import random class Player: # A Player keeps track of service probability and score def __init__(self, prob): # Create a player with this probability self.prob = prob self.score = 0 def winsServe(self): # RETURNS true with probability self.prob return random() <= self.prob def incScore(self): # Add a point to this player's score self.score = self.score + 1 def getScore(self): # RETURN this player's current score return self.score Python Programming, 2/e
The Complete Program Python Programming, 2/e class RBallGame: # A RBallGame represents a game in progress. A game as two players # and keeps track of which one is currently serving. def __init__(self, probA, probB): # Create a new game having players with the given probs. self.playerA = Player(probA) self.playerB = Player(probB) self.server = self.playerA # Player A always serves first def play(self): # Play the game to completion while not self.isOver(): if self.server.winsServe(): self.server.incScore() else: self.changeServer() def isOver(self): # RETURNS game is finished (i.e. one of the players has won). a,b = self.getScores() return a == 15 or b == 15 or \ (a == 7 and b == 0) or (b==7 and a == 0) def changeServer(self): # Switch which player is serving if self.server == self.playerA: self.server = self.playerB self.server = self.playerA def getScores(self): # RETURNS the current scores of player A and player B return self.playerA.getScore(), self.playerB.getScore() Python Programming, 2/e
The Complete Program Python Programming, 2/e class SimStats: # SimStatistics handles accumulation of statistics across multiple # (completed) games. This version tracks the wins and shutouts for # each player. def __init__(self): # Create a new accumulator for a series of games self.winsA = 0 self.winsB = 0 self.shutsA = 0 self.shutsB = 0 def update(self, aGame): # Determine the outcome if aGame and update statistics a, b = aGame.getScores() if a > b: # A won the game self.winsA = self.winsA + 1 if b == 0: self.shutsA = self.shutsA + 1 else: # B won the game self.winsB = self.winsB + 1 if a == 0: self.shutsB = self.shutsB + 1 def printReport(self): # Print a nicely formatted report n = self.winsA + self.winsB print "Summary of", n , "games:" print print " wins (% total) shutouts (% wins) " print "--------------------------------------------" self.printLine("A", self.winsA, self.shutsA, n) self.printLine("B", self.winsB, self.shutsB, n) def printLine(self, label, wins, shuts, n): template = "Player %s: %4d %5.1f%% %11d %s" if wins == 0: # Avoid division by zero! shutStr = "-----" else: shutStr = "%4.1f%%" % (float(shuts)/wins*100) print template % (label, wins, float(wins)/n*100, shuts, shutStr) Python Programming, 2/e
The Complete Program Python Programming, 2/e def printIntro(): print "This program simulates games of racquetball between two" print 'players called "A" and "B". The ability of each player is' print "indicated by a probability (a number between 0 and 1) that" print "the player wins the point when serving. Player A always" print "has the first serve.\n" def getInputs(): # Returns the three simulation parameters a = input("What is the prob. player A wins a serve? ") b = input("What is the prob. player B wins a serve? ") n = input("How many games to simulate? ") return a, b, n def main(): printIntro() probA, probB, n = getInputs() # Play the games stats = SimStats() for i in range(n): theGame = RBallGame(probA, probB) # create a new game theGame.play() # play it stats.update(theGame) # get info about completed game # Print the results stats.printReport() Python Programming, 2/e
Case Study: Dice Poker Objects are very useful when designing graphical user interfaces. Let’s look at a graphical application using some of the widgets developed in previous chapters. Python Programming, 2/e
Program Specification Our goal is to write a program that allows a user to play video poker using dice. The program will display a hand consisting of five dice. Python Programming, 2/e
Program Specification The basic rules The player starts with $100 Each round costs $10 to play. This amount is subtracted from the user’s money at the start of the round. The player initially rolls a completely random hand (all 5 dice are rolled). The player gets two chances to enhance the hand by rerolling some or all of the dice. Python Programming, 2/e
Program Specification At the end of the hand, the player’s money is updated according to the following payout schedule: Hand Pay Two Pairs 5 Three of a Kind 8 Full House (A Pair and a Three of a Kind) 12 Four of a Kind 15 Straight (1-5 or 2-6) 20 Five of a Kind 30 Python Programming, 2/e
Program Specification Since we want a nice graphical interface, we will be interacting with our program through mouse clicks. The interface should have: The current score (amount of money) is constantly applied. The program automatically terminates if the player goes broke. The player may choose to quit at appropriate points during play. The interface will present visual cues to indicate what is going on at any given moment and what the valid user responses are. Python Programming, 2/e
Identifying Candidate Objects The first step is to analyze the program description and identify some objects that will be useful in solving the problem. This game involves dice and money. Are they good object candidates? On their own, a single die and the money can be represented as numbers. Python Programming, 2/e
Identifying Candidate Objects However, the game uses five dice, and we need to be able to roll all or a selection of the dice, as well as analyze the score. This can be encapsulated in a Dice class. Python Programming, 2/e
Identifying Candidate Objects Here are some obvious operations to implement: Constructor – Create the initial collection rollAll – Assign random values to each of the five dice roll – Assign a random value to some subset of the dice, while maintaining the current value of the others. Python Programming, 2/e
Identifying Candidate Objects values – Return the current values of the five dice score – Return the score for the dice The entire program can be thought of as an object. Let’s call the class PokerApp. The PokerApp object will keep track of the current amount of money, the dice, the number of rolls, etc. PokerApp will use a method called run to start the game. Python Programming, 2/e
Identifying Candidate Objects Another component of the game is the user interface. A good way to break down the complexity of a more sophisticated problem is to separate the UI from the main program. This is often called the model-view approach, where the program implements some model and the interface is a view of the current state of the model. Python Programming, 2/e
Identifying Candidate Objects We can encapsulate the decisions about the interface in a separate interface object. One advantage of this approach is that we can change the look and feel of the program by substituting a different interface object. Let’s call our interface object PokerInterface. Python Programming, 2/e
Implementing the Model The Dice class implements a collection of dice, which are just changing numbers. The obvious representation is a list of five ints. The constructor needs to create a list and assign some initial values. Python Programming, 2/e
Implementing the Model def __init__(self): self.dice = [0]*5 self.rollAll() This code first creates a list of five zeroes. Then they need to be set to random values. We need methods to roll selected dice and to roll all of the dice. Python Programming, 2/e
Implementing the Model Since rolling all dice is a special case of rolling selected dice, we can implement the former with the latter. We can specify which dice to roll by passing a list of indexes. For example, roll([0,3,4]) will roll the dice in positions 0, 3, and 4. We can use a loop to go through the list, generating a new random value for each listed position. Python Programming, 2/e
Implementing the Model def roll(self, which) for pos in which: self.dice[pos] = randint(1,6) We can use roll to implement rollAll… def rollAll(self): self.roll(range(5)) Here, range(5) is used to generate a list of all the indexes. Python Programming, 2/e
Implementing the Model The values function returns the values of the dice so they can be displayed. def values(self): return self.dice[:] Why did we create a copy of the dice list by slicing it? If a Dice client modifies the list it gets back from values, it will not affect the original copy stored in the Dice object. Python Programming, 2/e
Implementing the Model The score method will determine the worth of the current dice. We need to examine the values and determine whether we have any of the patterns in the table. Let’s return a string with what the hand is and an int that gives the payoff amount. Python Programming, 2/e
Implementing the Model We can think of this function as a multi-way decision, checking for each possible hand. The order that we do the check is important! A full house also contains a three of a kind, but the payout should be for a full house! Python Programming, 2/e
Implementing the Model One simple way to check the hand is to create a list of the counts of each value. counts[i] will be the number of times that i occurs in the roll. If the dice are [3,2,5,2,3], then the count list will be [0,0,2,2,0,1,0]. counts[0] will always be 0 since dice go from 1 – 6. Python Programming, 2/e
Implementing the Model With this approach, checking for a full house entails looking for a 3 and a 2 in counts. def score(self): counts = [0] * 7 for value in self.dice: counts[value] = counts[value] + 1 Python Programming, 2/e
Implementing the Model if 5 in counts: return "Five of a Kind", 30 elif 4 in counts: return "Four of a Kind", 15 elif (3 in counts) and (2 in counts): return "Full House", 12 elif (not (3 in counts)) and (not (2 in counts)) \ and (counts[1]==0 or counts[6] == 0): return "Straight", 20 elif 3 in counts: return "Three of a Kind", 8 elif counts.count(2) == 2: return "Two Pairs", 5 else: return "Garbage", 0 Since we’ve already checked for 5, 4, and 3 of a kind, checking that there are no pairs -- (not (2 in counts)) guarantees that the dice show five distinct values. If there is no 6, then the values must be 1-5, and if there is no 1, the values must be 2-6. Python Programming, 2/e
Implementing the Model Let’s try it out! >>> from dice import Dice >>> d = Dice() >>> d.values() [2, 3, 2, 6, 3] >>> d.score() ('Two Pairs', 5) >>> d.roll([3]) >>> d.values() [2, 3, 2, 2, 3] >>> d.score() ('Full House', 12) Python Programming, 2/e
Implementing the Model We now are at the point where we can implement the poker game. We can use top-down design to flesh out the details and suggest which methods will need to be implemented in the PokerInterface class. Initially, PokerApp will need to keep track of the dice, the amount of money, and the interface. Let’s initialize these values first. Python Programming, 2/e
Implementing the Model class PokerApp: def __init__(self): self.dice = Dice() self.money = 100 self.interface = PokerInterface() To run the program, we create an instance of this class and call its run method. The program will loop, allowing the user to continue playing hands until they are either out of money or choose to quit. Python Programming, 2/e
Implementing the Model Since it costs $10 to play a hand, we can continue as long as self.money >= 10. Determining whether the player wants to continue or not must come from the user interface. Python Programming, 2/e
Implementing the Model def run(self): while self.money >= 10 and self.interface.wantToPlay(): self.playRound() self.interface.close() The interface.close() call at the bottom will let us do any necessary clean-up, such as printing a final message, closing graphics windows, etc. Now we’ll focus on the playRound method. Python Programming, 2/e
Implementing the Model Each round consists of a series of rolls. Based on the rolls, the player’s score will be adjusted. def playRound(self): self.money = self.money – 10 self.interface.setMoney(self.money) self.doRolls() result, score = self.dice.score() self.interface.showResult(result, score) self.money = self.money + score self.interface.setMoney(self.money) Python Programming, 2/e
Implementing the Model When new information is to be presented to the user, the proper method from interface is invoked. The $10 fee to play is first deducted, and the interface is updated with the new amount of money remaining. The program processes a series of rolls (doRolls), displays the result, and updates the money. Python Programming, 2/e
Implementing the Model Lastly, we need to implement the dice rolling process. Initially, all the dice are rolled. Then, we need a loop that continues rolling user-selected dice until either the user quits or the limit of three rolls is reached. rolls keeps track of how many times the dice have been rolled. Python Programming, 2/e
Implementing the Model def doRolls(self): self.dice.rollAll() roll = 1 self.interface.setDice(self.dice.values()) toRoll = self.interface.chooseDice() while roll < 3 and toRoll != []: self.dice.roll(toRoll) roll = roll + 1 self.interface.setDice(self.dice.values()) if roll < 3: toRoll = self.interface.chooseDice() Whew! We’ve completed the basic functions of our interactive poker program. We can’t test it yet because we don’t have a user interface… Python Programming, 2/e
A Text-Based UI In the process of designing PokerApp, we also developed a specification for a generic PokerInterface class. The interface must support methods for displaying information – setMoney setDice showResult Python Programming, 2/e
A Text-Based UI It also must have methods that allow input from the user – wantToPlay chooseDice These methods can be implemented in many different ways, producing programs that look quite different, even while the underlying model, PokerApp, remains the same. Python Programming, 2/e
A Text-Based UI Graphical interfaces are usually more complicated to build, so we might want to build a text-based interface first for testing and debugging purposes. We can tweak the PokerApp class so that the user interface is supplied as a parameter to the constructor. Python Programming, 2/e
A Text-Based UI def __init__(self, interface): self.dice = Dice() self.money = 100 self.interface = interface By setting the interface up as a parameter, we can easily use different interfaces with our poker program. Here’s a bare-bones text-based interface: Python Programming, 2/e
A Text-Based UI # textinter.py class TextInterface: def __init__(self): print "Welcome to video poker.“ def setMoney(self, amt): print "You currently have $%d." % (amt) def setDice(self, values): print "Dice:", values def wantToPlay(self): ans = raw_input("Do you wish to try your luck? ") return ans[0] in "yY“ def close(self): print "\nThanks for playing!" Python Programming, 2/e
A Text-Based UI def showResult(self, msg, score): print "%s. You win $%d." % (msg,score) def chooseDice(self): return input("Enter list of which to change ([] to stop) ") Using this interface, we can test our PokerApp program. Here’s a complete program: from pokerapp import PokerApp from textinter import TextInterface inter = TextInterface() app = PokerApp(inter) app.run() Python Programming, 2/e
A Text-Based UI Python Programming, 2/e Welcome to video poker. Do you wish to try your luck? y You currently have $90. Dice: [6, 4, 1, 1, 6] Enter list of which to change ([] to stop) [1] Dice: [6, 3, 1, 1, 6] Two Pairs. You win $5. You currently have $95. You currently have $85. Dice: [5, 1, 3, 6, 4] Dice: [5, 2, 3, 6, 4] Enter list of which to change ([] to stop) [] Straight. You win $20. You currently have $105. Do you wish to try your luck? n Thanks for playing! Python Programming, 2/e
Developing a GUI Now that we’ve verified that our program works, we can start work on the GUI user interface. This new interface will support the various methods found in the text-based version, and will likely have additional helper methods. Python Programming, 2/e
Developing a GUI Requirements The faces of the dice and the current score will be continuously displayed. The setDice and setMoney methods will be used to change these displays. We have one output method, showResult. One way we can display this information is at the bottom of the window, in what is sometimes called a status bar. Python Programming, 2/e
Developing a GUI We can use buttons to get information from the user. In wantToPlay, the user can choose between rolling the dice or quitting by selecting the “Roll Dice” or “Quit” buttons. To implement chooseDice, we could have a button to push for each die to be rolled. When done selecting the dice to roll, the “Roll Dice” button could be pushed. Python Programming, 2/e
Developing a GUI We could allow the users to change their mind on which dice to choose by having the button be a toggle that selects/unselects a particular die. This enhancement suggests that we want a way to show which dice are currently selected. We could easily “gray out” the pips on dice selected for rolling. Python Programming, 2/e
Developing a GUI We also need a way to indicate that we want to stop rolling and score the dice as they are. One way to do this could be by not having any selected dice and choosing “Roll Dice”. A more intuitive solution would be to add a new button called “Score”. Now that the functional aspects are decided, how should the GUI look? Python Programming, 2/e
Developing a GUI Python Programming, 2/e
Developing a GUI Our GUI makes use of buttons and dice. We can reuse our Button and DieView class from previous chapters! We’ll use a list of Buttons as we did in the calculator program in Chapter 11. The buttons of the poker interface will not be active all of the time. E.g., the dice buttons are only active when the user is choosing dice. Python Programming, 2/e
Developing a GUI When user input is required, the valid buttons for that interaction will be set active and the others set inactive., using a helper method called choose. The choose method takes a list of button labels as a parameter, activates them, and then waits for the user to click one of them. Python Programming, 2/e
Developing a GUI The return value is the label of the button that was clicked. For example, if we are waiting for the user to choose either the “Roll Dice” or “Quit” button, we could use this code: choice = self.choose(["Roll Dice", "Quit"]) if choice == ("Roll Dice"): … Python Programming, 2/e
Developing a GUI def choose(self, choices): buttons = self.buttons # activate choice buttons, deactivate others for b in buttons: if b.getLabel() in choices: b.activate() else: b.deactivate() # get mouse clicks until an active button is clicked while True: p = self.win.getMouse() if b.clicked(p): return b.getLabel() Python Programming, 2/e
Developing a GUI The DieView class will be basically the same as we used before, but we want to add a new feature – the ability to change the color of a die to indicate when it is selected for rerolling. The DieView constructor draws a square and seven circles to represent where the pips appear. setValue turns on the appropriate pips for a given value. Python Programming, 2/e
Developing a GUI Here’s the setValue method as it was: def setValue(self, value): # Turn all the pips off for pip in self.pips: pip.setFill(self.background) # Turn the appropriate pips back on for i in self.onTable[value]: self.pips[i].setFill(self.foreground) Python Programming, 2/e
Developing a GUI We need to modify the DieView class by adding a setColor method to change the color used for drawing the pips. In setValue, the color of the pips is determined by the value of the instance variable foreground. Python Programming, 2/e
Developing a GUI The algorithm for setColor seems straightforward. Change foreground to the new color Redraw the current value of the die The second step is similar to setValue, but setValue requires the value to be sent as a parameter, and dieView doesn’t store this value anywhere. Once the pips have been turned on the value is discarded! Python Programming, 2/e
Developing a GUI To implement setColor, we tweak setValue so that it remembers the current value: self.value = value This line stores the value parameter in an instance variable called value. With the modification to setValue, setColor is a breeze. Python Programming, 2/e
Developing a GUI def setColor(self, color): self.foreground = color self.setValue(self.value) Notice how the last line calls setValue to draw the die, passing along the value from the last time setValue was called. Now that the widgets are under control, we can implement the poker GUI! The constructor will create all the widgets and set up the interface for later interactions. Python Programming, 2/e
Developing a GUI Python Programming, 2/e class GraphicsInterface: def __init__(self): self.win = GraphWin("Dice Poker", 600, 400) self.win.setBackground("green3") banner = Text(Point(300,30), "Python Poker Parlor") banner.setSize(24) banner.setFill("yellow2") banner.setStyle("bold") banner.draw(self.win) self.msg = Text(Point(300,380), "Welcome to the dice table.") self.msg.setSize(18) self.msg.draw(self.win) self.createDice(Point(300,100), 75) self.buttons = [] self.addDiceButtons(Point(300,170), 75, 30) b = Button(self.win, Point(300, 230), 400, 40, "Roll Dice") self.buttons.append(b) b = Button(self.win, Point(300, 280), 150, 40, "Score") b = Button(self.win, Point(570,375), 40, 30, "Quit") self.money = Text(Point(300,325), "$100") self.money.setSize(18) self.money.draw(self.win) Python Programming, 2/e
Developing a GUI Did you notice that the creation of the dice and their associated buttons were moved into a couple of helper methods? def createDice(self, center, size): center.move(-3*size,0) self.dice = [] for i in range(5): view = ColorDieView(self.win, center, size) self.dice.append(view) center.move(1.5*size,0) def addDiceButtons(self, center, width, height): center.move(-3*width, 0) for i in range(1,6): label = "Die %d" % (i) b = Button(self.win, center, width, height, label) self.buttons.append(b) center.move(1.5*width, 0) center is a Point variable used to calculate the positions of the widgets. Python Programming, 2/e
Developing a GUI The methods setMoney and showResult display text in an interface window. Since the constructor created and positioned the Text objects, all we have to do is call setText! Similarly, the output method setDice calls the setValue method of the appropriate DieView objects in dice. Python Programming, 2/e
Developing a GUI def setMoney(self, amt): self.money.setText("$%d" % (amt)) def showResult(self, msg, score): if score > 0: text = "%s! You win $%d" % (msg, score) else: text = "You rolled %s" % (msg) self.msg.setText(text) def setDice(self, values): for i in range(5): self.dice[i].setValue(values[i]) Python Programming, 2/e
Developing the GUI The wantToPlay method will wait for the user to click either “Roll Dice” or “Quit”. The chooser helper method can be used. def wantToPlay(self): ans = self.choose(["Roll Dice", "Quit"]) self.msg.setText("") return ans == "Roll Dice" After the user clicks a button, setting msg to "" clears out any messages. Python Programming, 2/e
Developing the GUI The chooseDice method is a little more complicated – it will return a list of the indexes of the dice the user wishes to roll. In our GUI, the user chooses dice by clicking on the corresponding button. We need to maintain a list of selected buttons. Python Programming, 2/e
Developing a GUI Each time a button is clicked, that die is either chosen (its index appended to the list) or unchosen (its index removed from the list). The color of the corresponding dieView will then reflect the current status of the dice. Python Programming, 2/e
Developing a GUI Python Programming, 2/e def chooseDice(self): # choices is a list of the indexes of the selected dice choices = [] # No dice chosen yet while True: # Wait for user to click a valid button b = self.choose(["Die 1", "Die 2", "Die 3", "Die 4", "Die 5", "Roll Dice", "Score"]) if b[0] == "D": # User clicked a die button i = eval(b[4]) - 1 # Translate label to die index if i in choices: # Currently selected, unselect it choices.remove(i) self.dice[i].setColor("black") else: # Currently unselected, select it choices.append(i) self.dice[i].setColor("gray") else: # User clicked Roll or Score for d in self.dice: # Revert appearance of all dice d.setColor("black") if b == "Score": # Score clicked, ignore choices return [] elif choices != []: # Don't accept Roll unless some return choices # dice are actually selected Python Programming, 2/e
Developing a GUI The only missing piece of our interface class is the close method. To close the graphical version, we just need to close the graphics window. def close(self): self.win.close() Python Programming, 2/e
Developing a GUI Lastly, we need a few lines to get the graphical poker playing program started! We use GraphicsInterface in place of TextInterface. inter = GraphicsInterface() app = PokerApp(inter) app.run() Python Programming, 2/e
OO Concepts The OO approach helps us to produce complex software that is more reliable and cost-effective. OO is comprised of three principles: Encapsulation Polymorphism Inheritance Python Programming, 2/e
Encapsulation As you’ll recall, objects know stuff and do stuff, combining data and operations. This packaging of data with a set of operations that can be performed on the data is called encapsulation. Encapsulation provides a convenient way to compose complex problems that corresponds to our intuitive view of how the world works. Python Programming, 2/e
Encapsulation From a design standpoint, encapsulation separates the concerns of “what” vs. “how”. The implementation of an object is independent of its use. The implementation can change, but as long as the interface is preserved, the object will not break. Encapsulation allows us to isolate major design decisions, especially ones subject to change. Python Programming, 2/e
Encapsulation Another advantage is that it promotes code reuse. It allows us to package up general components that can be used from one program to the next. The DieView and Button classes are good examples of this. Encapsulation alone makes a system object-based. To be object-oriented, we must also have the properties of polymorphism and inheritance. Python Programming, 2/e
Polymorphism Literally, polymorphism means “many forms.” When used in object-oriented literature, this refers to the fact that what an object does in response to a message (a method call) depends on the type or class of the object. Python Programming, 2/e
Polymorphism Our poker program illustrated one aspect of this by the PokerApp class being used with both TextInterface and GraphicsInterface. When PokerApp called the showDice method, the TextInterface showed the dice one way and the GraphicsInterface did it another way. Python Programming, 2/e
Polymorphism With polymorphism, a given line in a program may invoke a completely different method from one moment to the next. Suppose you had a list of graphics objects to draw on the screen – a mixture of Circle, Rectangle, Polygon, etc. Python Programming, 2/e
Polymorphism You could draw all the items with this simple code: for obj in objects: obj.draw(win) What operation does this loop really execute? When obj is a circle, it executes the draw method from the circle class, etc. Python Programming, 2/e
Polymorphism Polymorphism gives object-oriented systems the flexibility for each object to perform an action just the way that it should be performed for that object. Python Programming, 2/e
Inheritance The idea behind inheritance is that a new class can be defined to borrow behavior from another class. The new class (the one doing the borrowing) is called a subclass, and the other (the one being borrowed from) is called a superclass. This is an idea our examples have not included. Python Programming, 2/e
Inheritance Say we’re building an employee management system. We might have a class called Employee that contains general information common to all employees. There might be a method called homeAddress that returns an employee’s home address. Python Programming, 2/e
Inheritance Within the class of employees, we might distinguish between salaried and hourly employees with SalariedEmployee and HourlyEmployee, respectively. Each of these two classes would be a subclass of Employee, and would share the homeAddress method. Python Programming, 2/e
Inheritance Each subclass could have its own monthlyPay function, since pay is computed differently for each class of employee. Inheritance has two benefits: We can structure the classes of a system to avoid duplication of operations, e.g. there is one homeAddress method for HourlyEmployee and SalariedEmployee. New classes can be based on existing classes, promoting code reuse. Python Programming, 2/e
Inheritance We could have used inheritance to build the DieView class. Our first DieView class did not provide a way to change the appearance of the dir. Rather than modifying the original class definition, we could have left the original alone and created a new subclass called ColorDieView. Python Programming, 2/e
Inheritance A ColorDieView is just like DieView, except it has an additional method! class ColorDieView(DieView): def setValue(self, value): self.value = value DieView.setValue(self, value) def setColor(self, color): self.foreground = color self.setValue(self.value) Python Programming, 2/e
Inheritance The first line (class ColorDieView(DieView): ) says that we are defining a new class ColorDieView that is based on (i.e. is a subclass of) DieView. Inside the new class we define two methods. The second method, setColor, adds the new operation. To make it work, setValue also needed to be slightly modified. Python Programming, 2/e
Inheritance The setValue method in ColorDieView redefines or overrides the definition of setValue that was provided in the DieView class. The setValue method in the new class first stores the value and then relies on the setValue method of the superclass DieView to actually draw the pips. Python Programming, 2/e
Inheritance The normal approach to set the value, self.setValue(value), would refer to the setValue method of the ColorDieView class, since self is an instance of ColorDieView. To call the superclass’s setValue method, it’s necessary to put the class name where the object would normally go: DieView.setValue(self,value) Python Programming, 2/e
Inheritance DieView.setValue(self,value) The actual object to which the method is applied is sent as the first parameter. Python Programming, 2/e