MIME-Version: 1.0 Content-Location: file:///C:/F48430D5/Week5.htm Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset="us-ascii" Week 5

Week = 5

Variables, Decision Structures, and Exceptions

Indiana University

Computer Science A202 / A598

and Informatics I211

 

This week’s success strategy

<= ![if !supportLists]>n   If you are having trouble solving a problem, notice what problem solving techn= ique you are using

<= ![if !supportLists]>q   <= /span>could you use it better?

<= ![if !supportLists]>q   <= /span>would it be better to use another technique?<= /o:p>

<= ![if !supportLists]>n&nb= sp;  A very general and powerful problem solving technique: break big problems up into smaller problems

<= ![if !supportLists]>q   <= /span>develop and test programs incrementally=

<= ![if !supportLists]>q   <= /span>for difficult debugging, save a copy of the progra= m and then start removing code to simplify things until the problem is isolated.<= o:p>

This = week

<= ![if !supportLists]>n   Variables

<= ![if !supportLists]>q   <= /span>parameter passing

<= ![if !supportLists]>q   <= /span>aliasing

<= ![if !supportLists]>q   <= /span>global variables

<= ![if !supportLists]>n   if statement

<= ![if !supportLists]>q   <= /span>boolean expressions

<= ![if !supportLists]>n   Raising exceptions

Param= eter passing is by-value

<= ![if !supportLists]>n   Only the value of an actual parameter is passed to a function<= /span>

<= ![if !supportLists]>q   <= /span>assigning a new value to a parameter variable chan= ges only that variable

<= ![if !supportLists]>q   <= /span>if a variable is the actual parameter of the call = to the current function, its value is not affected by the assignment

>>> x =3D 2

>>> def fun(y):

        y =3D 3

  

>>> fun(x)

>>> x

2

<= ![if !supportLists]>q   <= /span>it works like this in most, but not all, languages=

Alias= ing

<= ![if !supportLists]>n   In English, alias means an alternate name

<= ![if !supportLists]>n   In programming, aliasing occurs whenever there is more than one = way to access an object or data structure

<= ![if !supportLists]>q   <= /span>mutable objects may be changed through an alias

>>> lst1 =3D [1]

>>> lst2 =3D lst1

>>> lst2[0] =3D 3

>>> lst1<= /span>

[3]

 <= /p>

 

Alias= ing of parameters

<= ![if !supportLists]>n   When a function's actual parameter is a variable reference, the corresponding fo= rmal parameter becomes an alias for the actual parameter.

<= ![if !supportLists]>q   <= /span>So though assignments to a formal parameter do not change any other variable, assignment to part of a data structure passed as= an argument will be visible to the caller

>>> def fun(lst2):

       lst2[0] =3D 5

 

>>> fun(lst1)

>>> lst1

[5] =

 =

Global variable assignment

<= ![if !supportLists]>n    (This is not in your text)

<= ![if !supportLists]>n    A global variable is one that is not local = to a function (or class)

<= ![if !supportLists]>n    A variable must be declared global before it can be assigned from within a function

>>> x =3D 0

>>> def fun():

        global x # note = use of keyword global

        x =3D 3

  

>>> fun()=

>>> x

3

>>> def fun():<= /o:p>

        x =3D 5

  

>>> fun()

>>> x

3

<= ![if !supportLists]>n    Global variables do not need to be declared if they are only referenced (not assigned)

One-a= rmed if statement

<= ![if !supportLists]>n   Syntax:

<test expression> :
<then block>

<= ![if !supportLists]>q   <= /span><block> is a sequence of statements (general= ly indented)

<= ![if !supportLists]>n     in Python documentation= a block is called a suite

<= ![if !supportLists]>n   Semantics (meaning): <then block> is executed only if <test expression> f= irst evaluates to a true value

<= ![if !supportLists]>n   A true value is any value other than the false values: None, False, zero (of any numeric type), any empty sequence, or any empty dictionary (= we haven't see dictionaries yet)

>>> if 'abc'[1:-5]: # ''

        print 3

  

>>>

Two-a= rmed if statement

<= ![if !supportLists]>n      Syntax:

    if <test expression> :
   <then block>
else:
  
<else block><= o:p>

<= ![if !supportLists]>n      Semantics: if <test expression> evaluates to a true value, execute <then block>, and otherwise execute <else block>

One- = and two-armed if flow charts

If statement examples

<= ![if !supportLists]>n   One- and two-armed if statements in functions equivalent to the built-in abs<= /b> function

def oneArmedAbs1(x):      def oneArmedAbs2(x):

    if x <= 0:        &= nbsp;         if x < 0:=

        return -x        =           x =3D -x

    return x<= span style=3D'mso-spacerun:yes'>        =            return x

 

def twoArmedAbs(x):

    if x <= 0:

        return -x

    else:

        return x

<= ![if !supportLists]>n   Which is better style, and why?

=  

Gener= al if statement with elif

<= ![if !supportLists]>n    Syntax:

if <test expression> :
<then block>

elif <test expression> :
<then block>

[e= lse:

      <else block>]

<= ![if !supportLists]>q   read elif as = or else, if

<= ![if !supportLists]>q   <= /span>As usual in syntactic notation, square brackets indicate their conte= nts is optional and ellipsis "…" indicates the preceding syntactic element may be repeated any number of times (including zero)=

<= ![if !supportLists]>n    Semantics: evaluate <test expression>s in or= der until one is true, and then execute the associated <then block>. If no <test expression> is true, execute <else block> if it is presen= t

Else-= if flow chart

Else-= if example

<= ![if !supportLists]>n    The following both implement the mathematical sign function

def signWithElif(x):

    if x <= 0:

        return -1

    elif x = =3D=3D 0:

        return 0

    else: # x= > 0

        return 1

def signWithoutElif(x):

    if x <= 0:

        return -1

    else:

        if x =3D=3D 0:

        =     return 0

        else: # x > 0

        =     return 1

Exerc= ise: ordinal suffix

<= ![if !supportLists]>n   &nb= sp; The ordinal suffix of 1, 2, and 3 is st, nd, and rd= , respectively, while that of integers larger than 3 is th.=

<= ![if !supportLists]>n   &nb= sp; Define the function ordinalSuffix(n) that returns the ordinal suffix of n (assuming n is a positive integer).

<= ![if !supportLists]>n   &nb= sp; Two solutions:

def ordinalSuffix(n):

    if n =3D= =3D 1:

        return 'st'

    elif n = =3D=3D 2:

        return 'nd'

    elif n = =3D=3D 3:

        return 'rd'

    else:

        return 'th'

 

def ordinalSuffix2(n):

    if n <= 4:

        return ['st', 'nd', 'rd'][n-1]

    else:

        return 'th'

Test expressions

<= ![if !supportLists]>n   In Python any expression may be used as a test expression, since all values are interpreted as true or false

<= ![if !supportLists]>n   The literals True and False, of type bool, are represent t= he boolean values true and false

<= ![if !supportLists]>n   A predicate is a function that returns a boolean value

>>> callable(open)

True

>>> callable(3)

False

Relat= ional operators

<= ![if !supportLists]>n   The relational operators are also predicates

<= ![if !supportLists]>q   < <= span style=3D'font-size:10.0pt;font-family:Arial;mso-bidi-font-family:Arial; mso-bidi-language:#AC45'>means less than

<= ![if !supportLists]>q   <=3D means less than or equal<= /p>

<= ![if !supportLists]>q   > means greater than

<= ![if !supportLists]>q   >=3D means greater than or equal

<= ![if !supportLists]>q   =3D=3D means equal (do not confuse with =3D)

<= ![if !supportLists]>q   <= /span>!=3D means= not equal

<= ![if !supportLists]>q   is (is not) test if values are (are no= t) the same

<= ![if !supportLists]>q   <= /span>in (n= ot in) test sequence (non-)membership

<= ![if !supportLists]>n   &nb= sp; <value> in <sequence> is true if <value>= is =3D=3D to some element of the sequence

<= ![if !supportLists]>n   &nb= sp; example: 'b' in 'abc' and 2 not in [1, 3] are true

Order= ing of all things

<= ![if !supportLists]>n    The ordering operators (<, <=3D, >, &g= t;=3D) can be used to compare any two value

<= ![if !supportLists]>n    They reflect the usual ordering of numbers, but how are other values ordered?

<= ![if !supportLists]>n    Characters are ordered by the ordinal values<= /o:p>

<= ![if !supportLists]>q   <= /span>returned by the ord function

<= ![if !supportLists]>n    Sequences of the same type are ordered lexicogr= aphically

<= ![if !supportLists]>q   <= /span>the order is determined by the first pair of corresponding elements = that are not equal

<= ![if !supportLists]>q   <= /span>this gives the usual alphabetical ordering on strings

>>> ['Month' < 'Monty',
  'ABC' < 'Aa',
  (1, 'Z', 3) < (1, 'a', 3)= ]

[True, True, True]

<= ![if !supportLists]>n   &nb= sp; Object classes can have methods that determine the order of their instances

Equal= ity and sameness

<= ![if !supportLists]>n   Numbers are equal only when they are the same, but is this true of all values, such as sequences?

<= ![if !supportLists]>n   Two sequences are the same if they are the same object, but equal if they are t= he same type of sequence and corresponding elements are equal

<= ![if !supportLists]>n   (transcript)

<= ![if !supportLists]>n   Two object references are the same if they refer to the same location in memory, but if they are instances of the same class they are equal if their classes __eq__ method says they are

Exerc= ise

<= ![if !supportLists]>n   Define a function that takes a number from 1 through 12 and returns the number of = days in the corresponding month, ignoring leap years

<= ![if !supportLists]>n   Answer

def daysInMonth(month):

    if month = in [9, 4, 6, 11]:

        return 30

    elif mont= h =3D=3D 2:

        return 28

    else:

        return 31

Contr= olling execution when importing

<= ![if !supportLists]>n   The variable __name__ contains the name of the module if the module is imported, and '__main__' if the module is run as an application=

<= ![if !supportLists]>n   It is customary for application modules to end with the following, rather than just a main() call

if __name__ =3D=3D '__main__':

    main()

<= ![if !supportLists]>n   Why might the advantage of this be?

<= ![if !supportLists]>n   It allows the module to be imported so its functions can be tested or otherwise used without of running the application

Excep= tions raised by the system

<= ![if !supportLists]>n    We say an exception has been raised when the system detects an error that results in the program terminating with a mess= age indicating the nature of the error and traceback telling us where it occurr= ed

>>> 'abc'[3]

 

Traceback (most recent call last):

  File "<pyshell#29>", line 1, in -toplevel-

    'abc'[3]<= o:p>

IndexError: string index out of range

>>>

<= ![if !supportLists]>n    What are other situations in which Python raises an exception?

<= ![if !supportLists]>n    Partial answer

<= ![if !supportLists]>q   <= /span>trying to open a file that does not exist

<= ![if !supportLists]>q   <= /span>dividing by zero

<= ![if !supportLists]>q   <= /span>sending a message to a value that is not an object or an object that does not have the indicated method

<= ![if !supportLists]>q   <= /span>trying to call a value that is not a function

<= ![if !supportLists]>q   <= /span>passing math.sqrt a negative number

Excep= tions in program execution

<= ![if !supportLists]>n   Programs rely on may aspects of their data and operating environment that may not be true due to

<= ![if !supportLists]>q   <= /span>errors in other parts of the program

<= ![if !supportLists]>q   <= /span>errors or exceptional situations in the data fed to the program, or

<= ![if !supportLists]>q   <= /span>failures in the supporting computing environment

<= ![if !supportLists]>n   If a program fails to check for such exceptional situations, it may produce bo= gus results or "blow up" with an exception raised by the system that = the user of the program is unable to interpret

<= ![if !supportLists]>q   <= /span>In some other languages (such as C and C++) such errors may cause the program, or even the entire computer,  to "crash" without even = giving a message, but Python is designed to prevent this

Robust programs      = ;  

<= ![if !supportLists]>n&nb= sp;  Programs that check for errors and exception= al situations and give meaningful error messages and when possible take measur= es to recover from exceptional situation are said to be robust

<= ![if !supportLists]>n   Robustness is one of the most important aspects of program quality <= /p>

<= ![if !supportLists]>q   <= /span>Making a robust program can be several times as mu= ch work as writing an otherwise similar fragile (non-robust) program

<= ![if !supportLists]>q   <= /span>It is estimated that 80-90% of the instructions in commercial programs is there just to make the program robust

<= ![if !supportLists]>n   Small programs used only occasionally by a few&n= bsp; knowledgeable users generally need not be very robust

<= ![if !supportLists]>q   <= /span>but even then some error checking is generally worthwhile because it makes debugging easier

Deali= ng with exceptions

<= ![if !supportLists]>n   Bad data or other exceptional circumstances generally mean the program cannot continue in its ordinary way, so what should it do?

<= ![if !supportLists]>n   Many applications just prints an error message and terminate appropriately<= /o:p>

<= ![if !supportLists]>n   What should a function written for use in a variety of situations in other progr= ams do?

<= ![if !supportLists]>n   Answer: let the calling program decide how to deal with the problem by either<= /o:p>

<= ![if !supportLists]>q   <= /span>returning a value indicating an error or failure of some kind

<= ![if !supportLists]>n   &nb= sp; example: string.find returns -1 if the substring is not found=

<= ![if !supportLists]>q   <= /span>raising an exception

Raisi= ng exceptions

<= ![if !supportLists]>n   The raise statement raises or throws an exception, which m= ay be any value

<= ![if !supportLists]>q   <= /span>syntax: raise <exception value expression>

<= ![if !supportLists]>q   <= /span>a string containing an appropriate error message is the simplest kind of useful exception value

<= ![if !supportLists]>n   Unless the exception is caught by a program try statement, the progr= am will terminate

<= ![if !supportLists]>q   <= /span>in most contexts (such as applications) terminatio= n is indicated with a traceback message indicating where the exception was raised followed by the printed form of the exception value

<= ![if !supportLists]>q   <= /span>the traceback message indicates all the function c= alls that had been made but not returned at the time the exception was raised

Probl= em: improving the daysInMonth function

 =

<= ![if !supportLists]>n   Modify daysInMonth program so it raises an exception if the month number is= not an integer from 1 through 12.

>>> daysInMonth(12)

31

>>> daysInMonth(13)

 

Traceback (most recent call last):

  File "<pyshell#4>", line 1, in -toplevel-<= /p>

    daysInMon= th(13)

  File "C:\home\202\c\5\misc.py", line 31, in daysInMonth

    raise 'Bad month: ' + str(month)

Bad month: 13

>>>

<= o:p> 

Bette= r daysInMonth function

<= ![if !supportLists]>n   Solution:

def daysInMonth(month):

    if month = not in range(1,13):

        raise 'Bad month: ' + str(month)

    if month = in [9, 4, 6, 11]:

        return 30

    elif mont= h =3D=3D 2:

        return 28

    else:

        return 31

<= ![if !supportLists]>n   It is often helpful to include the offending value in the error message

<= ![if !supportLists]>q   <= /span>This can cause problems if the value is a huge data structure with a string representation that goes on for pages!