Transcript File

Appendix O: Additional Python 2.2
Features
Outline
O.1
O.2
O.3
O.4
O.5
Introduction
Iterators
Generators
Nested Scopes
Internet and World Wide Web Resources
 2002 Prentice Hall. All rights reserved.
O.1 Introduction
• Overview of new features in Python 2.2 (e.g.,
iterators, generators and nested scopes) that allow
programmers to express algorithms more clearly
and simply
 2002 Prentice Hall. All rights reserved.
O.2 Iterators
• Special objects that define operations for
progressing through sequences
• Useful for many kinds of sequences, including
list-like objects (such as built-in types list and
tuple), program-defined container objects (e.g.,
trees) or unbounded sequences whose length is
unknown (e.g., input and output streams)
• __getitem__ intended for random attribute
access (e.g., index access for lists or dictionary
key lookups), rather than iteration
• Can be more efficient for processing a sequence
 2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Fig. O.1: NewRange.py
Class simulates range of
# __getitem__ used in a for loop.
Outline
integer values
class MyRange:
"""Simple class
to simulate
a range
values"""
Constructor
receives
valuesof
forinteger
parameters
start,
stop andNewRange.py
step
Constructor
calls range to generate sequence
def __init__( self, start, stop,
step ):
"""Class MyRange constructor; takes start, stop and step"""
of integers
Provides subscript access (using operator [])
self.__sequence = range( start, stop, step )
def __getitem__( self, subscript
):
Python
raises
Returns
element
"""Overridden sequence element access"""
IndexError
if subscript
stored at specified
subscriptlies out of bounds
return self.__sequence[ subscript ]
 2002 Prentice Hall.
All rights reserved.
Python 2.2b2 (#26, Nov 16 2001, 11:44:11) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> from NewRange import MyRange
>>> myRange = MyRange( 0, 10, 1 )
>>>
>>> print myRange[ 0 ]
0
>>> print myRange[ 8 ]
8
>>>
>>> for value in myRange:
...
print value,
...
0 1 2 3 4 5 6 7 8 9
Outline
Fig. O.1
__getitem__
method to emulate
iteration
 2002 Prentice Hall.
All rights reserved.
Python 2.2b2 (#26, Nov 16 2001, 11:44:11) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> from NewRange import MyRange
>>> myRange = MyRange( 0, 10, 1 )
>>>
>>> currentIndex = 0
>>>
>>> while 1:
...
try:
...
value = myRange[ currentIndex ]
...
except IndexError:
...
break
...
else:
...
print value,
...
currentIndex += 1
...
0 1 2 3 4 5 6 7 8 9
Outline
Fig. O.2 __getitem__
and for loops
 2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Fig. O.3: NewRangeIterator.py
# Iterator class that defines a sequence.
class RangeIterator:
"""Simple class to simulate a range"""
Outline
NewRangeIterator
.py
def __init__( self, start, stop, step ):
"""RangeIterator constructor; takes start, stop and step"""
self.__sequence = range( start, stop, step )
self.__nextValue = 0 # subscript of next value to produce
def __iter__( self ):
"""Returns iterator for object of class RangeIterator"""
return self
def next( self ):
"""Iterator method to produce next value in sequence"""
try:
value = self.__sequence[ self.__nextValue ]
except IndexError:
raise StopIteration
else:
self.__nextValue += 1
return value
def main():
Create object range1 that contains values 0-9
# create object of class RangeIterator, use for loop to iterate
range1 = RangeIterator( 0, 10, 1 )
print "Iterate over the values in range1 using a for loop:"
 2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
for value in range1:
print value,
Outline
Uses for loop to iterate over object’s elements
print
NewRangeIterator
Retrieve
iterator forcall
object
by calling
method iter
.py
class
RangeIterator,
next
to iterate
# create object of
range2 = RangeIterator( 0, 10, 1 )
range2Iterator = iter( range2 ) # retrieve iterator for range2
print "\nCall method next for range2Iterator:"
while 1:
next for an object’s iterator progresses through values in an object’s sequence
next raises StopIteration when there are no more values in the sequence
try:
value = range2Iterator.next()
except StopIteration:
break
else:
print value,
print
# create one object of class RangeIterator two iterators
# for that object
Objects can have more than one iterator
range3 = RangeIterator( 0, 10, 1 )
range3Iterator1 = iter( range3 )
range3Iterator2 = iter( range3 )
print "\nCall next for two iterators of the same object:"
 2002 Prentice Hall.
All rights reserved.
66
67
68
69
70
71
72
73
74
for i in range( Using
10 ): more than one iterator on the same object can
print "Loop iteration %d: range3Iterator1.next() = %d" % \
( i, range3Iterator1.next() )
print "Loop iteration %d: range3Iterator2.next() = %d" % \
( i, range3Iterator2.next() )
print
lead to subtleOutline
logic errors
NewRangeIterator
.py
if __name__ == "__main__":
main()
 2002 Prentice Hall.
All rights reserved.
Iterate over the values in range1 using a for loop:
0 1 2 3 4 5 6 7 8 9
Outline
Call method next for range2Iterator:
0 1 2 3 4 5 6 7 8 9
Call next for two iterators of the same object:
Loop iteration 0: range3Iterator1.next() = 0
Loop iteration 0: range3Iterator2.next() = 1
Loop iteration 1: range3Iterator1.next() = 2
Loop iteration 1: range3Iterator2.next() = 3
Loop iteration 2: range3Iterator1.next() = 4
Loop iteration 2: range3Iterator2.next() = 5
Loop iteration 3: range3Iterator1.next() = 6
Loop iteration 3: range3Iterator2.next() = 7
Loop iteration 4: range3Iterator1.next() = 8
Loop iteration 4: range3Iterator2.next() = 9
Traceback (most recent call last):
File "newrange3.py", line 74, in ?
main()
File "newrange3.py", line 67, in main
print "Loop iteration %d: range3Iterator1.next() = %d" % \
File "newrange3.py", line 24, in next
raise StopIteration
StopIteration
 2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Fig. O.4: GuessingGame.py
# Class and program to simulate computer guessing game.
import random
Outline
GuessingGame.py
class ComputerGuessingGame:
"""Class to guess a number randomly"""
def __init__( self, value, lowerBound = 0, upperBound = 10 ):
"""ComputerGuesser constructor; takes secret number, lower
and upper bounds"""
self.realValue =Keeps
valuevalue
within upper and lower bounds
# keep value within upper and lower bound
if value < lowerBound:
self.lower = value
else:
self.lower = lowerBound
if value > upperBound:
self.upper = value + 1
else:
self.upper = upperBound
def __iter__( self ):
"""Return iterator for object of class ComputerGuesser"""
Produces
return self
a series of random guesses
def next( self ):
"""Guesses a new value. If correct, raises StopIteration;
otherwise returns guess"""
guess = random.randrange( self.lower, self.upper )
 2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
If correct, raises StopIteration
Outline
if guess == self.realValue:
raise StopIteration
else:
return guess
GuessingGame.py
def main():
# retrieve an integer from the user
while 1:
try:
secretNumber = int(
raw_input( "Enter number for computer to guess: " ) )
except ValueError:
print "Please enter an integer."
else:
break
print
computerGuesser = ComputerGuessingGame( secretNumber )
numberOfWrongGuesses
= iterator
0
Implicitly creates
for ComputerGuessingGame
object computerGuesser
# print the incorrect guesses
for wrongGuess in computerGuesser:
numberOfWrongGuesses += 1
print "Computer guessed: %d" % wrongGuess
print "\nGot secret number after %d wrong guesses." % \
numberOfWrongGuesses
if __name__ == "__main__":
main()
 2002 Prentice Hall.
All rights reserved.
Enter number for computer to guess: 6
Computer
Computer
Computer
Computer
Computer
Computer
Computer
Computer
Computer
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
Outline
1
7
1
1
3
9
9
1
8
Got secret number after 9 wrong guesses
Enter number for computer to guess: 100
Computer
Computer
Computer
Computer
Computer
Computer
Computer
Computer
Computer
Computer
Computer
Computer
Computer
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
guessed:
31
41
61
77
92
80
11
46
43
31
21
6
7
Got secret number after 13 wrong guesses.
 2002 Prentice Hall.
All rights reserved.
O.3 Generators
• Functions that return iterators
• Resumable functions that are especially well
suited for computing the values of a recursive
sequence
• Special kind of functions that can suspend
computation, “remember” their local variables and
later resume where the previous computation left
off
 2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Fig. O.5: figO_05.py
# Inefficient, recursive fibonacci calls.
def fibonacci( n ):
Outline
figO_05.py
if n < 0:
raise ValueError, \
"Cannot computer fibonacci on negative number"
elif n == 0 or n == 1:
return n
else:
return fibonacci( n - 1 ) + fibonacci( n - 2 )
n = 0
value = 0
Compute smallest fibonacci( n ) > 1000
# compute smallest fibonacci( n ) > 1000
while value < 1000:
value = fibonacci( n )
n += 1
print "The smallest fibonacci number greater than 1000 is:", value
The smallest fibonacci number greater than 1000 is: 1597
 2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Outline
# Fig. O.6: figO_06.py
# fibonacci generator.
Import generators
Define fibonacci generator
from __future__ import generators
figO_06.py
Refers
def fibonacci():
to next value in the sequence
Return to value after the value indicated by nextItem
nextItem = 0 # next value in the sequence
beyondItem = 1 # value *after* the next value in the sequence
Keyword yield suspends execution and returns intermediate value
while 1:
yield nextItem
# return fibonacci( n )
# function resumes here when program calls next on
# fibonacci's
Functioniterator
resumes here when program calls next on
fibonacci’s iterator
# compute the next fibonacci( n ) and fibonacci( n + 1 )
nextItem, beyondItem
= beyondItem, nextItem + beyondItem
Create iterator
fibIterator = fibonacci() # create iterator for Fibonacci sequence
result = 0 Find smallest Fibonacci number greater than 1000
# find smallest Fibonacci number greater than 1000
while result < 1000:
result = fibIterator.next()
print "The smallest fibonacci number greater than 1000 is:", result
The smallest fibonacci number greater than 1000 is: 1597
 2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Fig O.7: figO_07.py
# fibonacci generator for nth Fibonacci sequence element.
Outline
Generator raises a StopIteration exception when it returns
from __future__ import generators
figO_07.py
def fibonacci( n ):
nextItem = 0 # next value in the sequence
beyondItem = 1 # value *after* the next value in the sequence
currentN = 0 # n for which the generator is producing a value
while currentN <= n:
yield nextItem # return fibonacci( n )
# compute the next fibonacci( n ) and fibonacci( n + 1 )
nextItem, beyondItem = beyondItem, nextItem + beyondItem
currentN += 1
while 1:
# retrieve number from user
try:
fibNumber = int( raw_input( "Enter a number: " ) )
except ValueError:
print "Please enter an integer."
else:
break
print
counter = 0
Python repeatedly
callsimplicitly
next to get
valuefirst
fortime
result
Iterator
created
fibonacci function is invoke
# print fibonacci( n ) for all n <= fibNumber
for result in fibonacci( fibNumber ):
print "fibonacci( %d ) = %d" % ( counter, result )
counter += 1
 2002 Prentice Hall.
All rights reserved.
Enter a number: 20
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
fibonacci(
Outline
0 ) = 0
1 ) = 1
2 ) = 1
3 ) = 2
4 ) = 3
5 ) = 5
6 ) = 8
7 ) = 13
8 ) = 21
9 ) = 34
10 ) = 55
11 ) = 89
12 ) = 144
13 ) = 233
14 ) = 377
15 ) = 610
16 ) = 987
17 ) = 1597
18 ) = 2584
19 ) = 4181
20 ) = 6765
 2002 Prentice Hall.
All rights reserved.
O.4 Nested Scopes
• Address how identifier lookup takes place in
nested functions
• Most useful for programs that employ a
functional-style of programming
• Nested scoping enables an inner function to access
variables that appear in the function’s outer scope
 2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Outline
# Fig. O.8: figO_08.py
# Nested functions.
def outer():Function
inner prints message to indicate that function is executing
figO_08.py
def inner(): Calls built-in function dir to print list of
print "\nFunction inner executing"
print "The objects in inner's scope are:", dir()
print "Function inner finishing"
print "Function outer executing"
print "The objects in outer's scope are:", dir()
inner()
print "\nFunction
outer
finishing"
Emphasize fact
that
inner can be accessed only
objects in the inner’s scope
in function outer’s local scope
print "The objects in the global scope are:"
print dir()
print "\nCalling function outer\n"
outer()
print "\nFunction outer finished"
 2002 Prentice Hall.
All rights reserved.
The objects in the global scope are:
['__builtins__', '__doc__', '__name__', 'outer']
Outline
Calling function outer
Function outer executing
The objects in outer's scope are: ['inner']
Function inner executing
The objects in inner's scope are: []
Function inner finishing
Function outer finishing
Function outer finished
 2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
# Fig O.9: CenterLength.py
# Functional definition of string justification.
Function
contained
def centerLength(
length
):
Outline
within function centerLength
Inner function calls object’s center method CenterLength.py
def centerString( stringValue ):
Return centered string
return stringValue.center(
length )
return centerString
Python 2.2b2 (#26, Nov 16 2001, 11:44:11) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import CenterLength
>>> centerString10 = CenterLength.centerLength( 10 )
>>>
>>> type( centerString10 )
<type 'function'>
>>>
>>> centerString10( "python" )
' python '
 2002 Prentice Hall.
All rights reserved.
Python 2.1.1 (#20, Jul 20 2001, 01:19:29) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
>>>
>>> import CenterLength
CenterLength.py:4: SyntaxWarning: local name 'length' in 'centerLength'
shadows
use of 'length' as global in nested scope 'centerString'
def centerLength( length ):
>>>
>>> centerString10 = CenterLength.centerLength( 10 )
>>> centerString10( "python" )
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "CenterLength.py", line 7, in centerString
return stringValue.center( length )
NameError: global name 'length' is not defined
Outline
Fig. O.10 Nested
scopes and older
versions of
Python.
 2002 Prentice Hall.
All rights reserved.