Extra Stuff for CS106 Victor Norman CS106

advertisement
Extra Stuff for CS106
Victor Norman
CS106
break and continue
• break and continue are both
ways to alter the
flow of a loop
• Can be used only inside a loop – for loop or
while loop.
break
• Exits the loop immediately
• Control jumps to the next statement after the
loop.
• Only exits the loop it is in.
– not an outer loop.
• Very useful if search for something and have
found it – no need to go on searching.
break Example
Searching for val in list nums:
found = False
for num in nums:
if num == i:
found = True
break
if found:
print “Found”, val
else:
print val, “is not in the list.”
continue
• Control jumps back up to top of loop
immediately.
• Very useful if you have a large body of
statement in a loop and know you don’t want
to run any more code for that time through
the loop
– E.g., very useful for filtering out data you are not
interested in.
continue Example
Filtering out items you don’t need to deal with:
only want to handle lines from a file that do not
start with # and are not blank lines.
for line in datafile:
if line.startswith(“#”):
continue
if line.strip() == “”:
continue
# 300 lines of code here to deal with
# good lines of data
Formatted Output
• Found in section 8.2.
• Problem: using just print it is very hard, if not
impossible to get your output to show up just
how you want it.
– how to print floats with 3 digits behind the
decimal?
– how to print a string in a “field width” of 20.
– etc.
Example
class Team
"""Represents a baseball team"""
def __init__(self, name, wins, losses):
self._name = name
self._wins = wins
self._losses = losses
# add getters, etc. here.
# Create a list of 4 teams
teams = [ Team("Pirates", 120, 42),
Team("Tigers", 105, 57),
Team("Yankees", 30, 132),
Team("Diamondbacks", 81, 81) ]
Example (2)
• How would we print out the four teams in a
nice table, with 20 spaces for the team name,
left-justified, 4 spaces for wins column, 4 for
losses, etc.?
Solution: use formatted output
• the % operator, on strings, is the format operator (not
mod operator).
• Syntax:
– spec-string % (tuple of values)
• if there is only one value, it does not have to be in a tuple
– produces a string as a result
– spec-string is a string containing multiple specifications,
one per number of values in tuple.
– i.e., if the tuple contains 3 items, there has to be 3
specifications in the spec-string.
– n-th item in the tuple uses the n-th specification in the
spec-string.
Example
n = 1
cheese = “Mozzarella”
weight = 3.1415926
print “%d. Width of %s is %8.3f kilograms.” %
(n, cheese, weight)
Output:
1. Weight of Mozzarella is
3.142 kilograms.
Specifications in spec-string
• Any character that is not a specification is
reproduced unchanged in the result.
• Specifications:
– %d: replace with given integer
– %s: replace with given string
– %f: replace with given float
– %%: put % in the output.
Exercise
• Write a print statement that prints this out:
Hello, my name is <name>.
where <name> is in a variable name.
• Could do this:
print “Hello, my name is ” + name + “.”
• Or, use %s.
• Answer:
print “Hello, my name is %s.” % name
Exercise 2
Write the code to print out:
0. Cheddar
1. Venezuelan Beaver Cheese
2. Roquefort
when given a list of strings cheeses. Use %d
for the number at the beginning.
Answer:
for i in range(len(cheeses)):
print “%d. %s” % (i, cheeses[i])
More details
• You can specify the field width and # digits
behind a decimal, justification, etc.
• %<minfieldwidth>.<precision>f
– %8.3f: put the float in a field of 8, with 3 digits
behind decimal point. Round it. Right justified.
– decimal point takes up one “space”.
• %<minfieldwidth>s: right-justified string in the
given field width
• %<minfieldwidth>d: similar to string.
Examples
print “%8.3f.*” % 4.5
4.500*
print “%-8.3f*” % 4.9999
5.000
*
(left justified, 3 spaces trail)
print “%-20s:” % “Pirates”
Pirates
:
print “%-20s:” % “Diamondbacks”
Diamondbacks
:
Error Handling
Big Question: What should a function do when it
cannot do its work because of bad input? E.g.,
def avg(items):
return sum(items) / len(items)
What bad inputs might we need to handle?
Option 1
def avg(items):
if len(items) == 0:
return "No items to average"
else:
return sum(items) / len(items)
res = avg(myItems)
if res == “No items to average”:
do_something()
else:
do_something_else()
Still doesn’t
handle a list like
this:
[“hi”, “there”]
Another example
You provide a nice Card class. Someone tries to
use it this way:
myCard = Card(87, “P”)
Should your code create this card? If so, it won’t
be able to print it, and might not work for other
stuff… What should it do instead?
(Constructors don’t return anything.)
Solution: Exceptions!
• Used to report unusual or error condition
from a function/method back to the caller.
• Terminology:
– an exception is raised or thrown in a
function/method when the error condition is
detected.
• e.g., ZeroDivisionError.
– an exception can be caught or handled by the
caller, or allowed to propagate up to the caller’s
caller.
Syntax to catch an exception
<code>
try:
<code to run, which might raise an
exception>
except <ExceptionType>:
<code to run when exception is caught>
<code>
(Lots of other parts available to this too, like
else, finally, etc.)
Another Example
Want code to read in a number from the user,
and make sure it is a good number…
while True:
try:
x = float(raw_input(“Enter a number: “))
break
except ValueError:
print “That was not a number!”
Raising an exception
• You can throw/raise an exception explicitly in
your code, e.g., when you get bad input:
class Card:
def __init__(self, denom, suit):
if suit not in (‘C’, ‘D’, ‘H’, ‘S’):
raise ValueError(“suit must be one of C, D, H,
or S”)
self._suit = suit
self._denom = denom
• What else should we check?
Full Code
class Card:
def __init__(self, denom, suit):
if not isinstance(denom, int):
raise TypeError(“denom must be an int”)
if denom not in range(2, 15):
raise ValueError(“denom must have value 2 to 14”)
if not isinstance(suit, str):
raise TypeError(“suit must be a string.”)
if suit not in (‘C’, ‘D’, ‘H’, ‘S’):
raise ValueError(“suit must be one of C, D, H, or S”)
# code here to store denom, suit, etc.
NOTE: now, when you have a Card object, you
*know* it has good state.
Pre-defined Exceptions/Errors
• https://docs.python.org/2/library/exceptions.
html#exception-hierarchy
• Exercise: fix the avg() call to raise appropriate
exceptions.
PYTHONPATH, etc.
Q: Where does python look when importing
modules?
A: The python interpreter looks at the
environment variable PYTHONPATH, which is a
list of directories. It looks in each directory for
the name of the module, and when found, loads
it.
Can see this PATH from within python…
sys.path
• To see the python path, start up python and do this:
>>> import sys
>>> print sys.path
['', '//anaconda/lib/python27.zip',
'//anaconda/lib/python2.7',
'//anaconda/lib/python2.7/plat-darwin',
'//anaconda/lib/python2.7/plat-mac',
'//anaconda/lib/python2.7/plat-mac/libscriptpackages', '//anaconda/lib/python2.7/lib-tk',
'//anaconda/lib/python2.7/lib-old',
'//anaconda/lib/python2.7/lib-dynload',
'//anaconda/lib/python2.7/site-packages',
'//anaconda/lib/python2.7/site-packages/Sphinx1.3.1-py2.7.egg', '//anaconda/lib/python2.7/sitepackages/aeosa', '//anaconda/lib/python2.7/sitepackages/setuptools-17.1.1-py2.7.egg']
pep8
• A “pep” is a Python Enhancement Proposal.
• Documents recording how the language
evolves – new features, new releases,
suggestions, etc.
• PEP-8 is the style guide
• You can run your code “through” pep8 to get
feedback on how well it conforms.
Example
Mac52078:distrib_yourself vtn2$ pep8 main.py
main.py:20:80: E501 line too long (85 > 79 characters)
main.py:21:80: E501 line too long (90 > 79 characters)
main.py:23:80: E501 line too long (89 > 79 characters)
main.py:25:80: E501 line too long (83 > 79 characters)
main.py:26:80: E501 line too long (89 > 79 characters)
main.py:30:80: E501 line too long (91 > 79 characters)
main.py:38:80: E501 line too long (88 > 79 characters)
main.py:47:1: E303 too many blank lines (3)
main.py:51:1: E302 expected 2 blank lines, found 1
main.py:69:1: W293 blank line contains whitespace
main.py:110:1: W293 blank line contains whitespace
main.py:124:80: E501 line too long (85 > 79 characters)
main.py:155:5: E301 expected 1 blank line, found 0
main.py:157:5: E301 expected 1 blank line, found 0
main.py:159:5: E301 expected 1 blank line, found 0
main.py:161:5: E301 expected 1 blank line, found 0
main.py:186:80: E501 line too long (83 > 79 characters)
main.py:187:80: E501 line too long (90 > 79 characters)
main.py:201:1: W293 blank line contains whitespace
main.py:224:9: E303 too many blank lines (2)
main.py:230:1: E302 expected 2 blank lines, found 1
main.py:269:1: W391 blank line at end of file
Dictionary intro
Big Question: How would you store the
information in a phone book in a data structure
in python?
Phone book maps names to :
• phone numbers
• addresses
Ideas?
• A class that stores all info (phone #, name,
address) and is stored in a list, sorted by
name?
• Q: What operations do you need to do? How
fast should they be?
• Q: Why is the data ordered in a phone book?
Dictionaries, in python
• type: dict
• one-way mappings, from “keys”  “values”.
– keys must be immutable.
– any value can be stored.
• each mapping is called an “entry”.
• unordered.
• Compared to list?:
– list: ordered mapping of consecutive integers to
values.
• mutable data structure
dict Operations
• Creation:
d = dict()
or
d = {}
d = { ‘a’: 3,
‘b’: ‘hello’,
33: 77,
(3, 4): [‘sword’, ‘potion’]}
(newlines above just for readability)
Lookup / Testing
• d[k] : gets value for key k. Error if k not a key
in d.
• len(d): returns # of entries in d.
• d.keys(): list of keys in d.
• if k in d: test if key k is in dictionary d.
• for k in d:
• d.items() returns list of tuples of (key, value)
pairs.
Insertion
: add entry k  v to dict d.
• if entry with key k exists already, replaces
value with v.
• d[k] = v
Example: count bases
bases = { ‘A’: 0, ‘G’: 0, ‘T’: 0, ‘C’: 0}
genome = “ATCGGGTCAAAAACCCTTGAGAGAG”
for base in bases:
bases[base] += 1
Example
# dictionary has one word per line.
f = open(“dictionary.txt”)
# map word length to list of words.
wordsByLenDict = {}
for w in f.readline():
w = w.strip() # remove newline, spaces.
lenw = len(w)
if lenw in wordsByLenDict:
wordsByLenDict[lenw].append(w)
wordsByLenDict[lenw].sort()
else:
# Add new entry mapping len to list of
# words, containing only w at this time.
wordsByLenDict[lenw] = [w]
Use the dictionary
• print all two letter words, one word per line
if 2 in wordsByLenDict: # 2 is the key
for w in wordsByLenDict[2]:
print w
• print all words, sorted by length.
keys = wordsByLenDict.keys()
keys.sort()
for k in keys:
for w in wordsByLenDict[k]:
print w
Summary: characteristics of dict
• Very fast insertion
• Very fast look-up.
• Keys much be unique and immutable.
– One-to-one or one-to-many relationship.
• Values can be anything.
• Unordered.
Consider the following…
• Consider this definition:
class Card:
def __init__(self, denom, suit):
legal_nums = range(2, 15)
legal_suits = (‘C’, ‘H’, ‘S’, ‘D’)
if denom not in legal_nums:
raise ValueError(“Bad #”)
if suit not in legal_suits:
raise ValueError(“Bad suit”)
• Every instance of Card has legal_nums and legal_suits
defined during instantiation. (Create 1000 full decks and
you create 52000 legal_nums and 52000 legal_suits, all
exactly the same.)
Class Variables
• legal_nums and legal_suits are not dependent
on the values passed in to the constructor…
• We could make them global… Yuck.
• Make them class variables. They exist in the
class only, not in each object.
Solution
class Card:
legal_nums = range(2, 15)
legal_suits = (‘C’, ‘H’, ‘S’, ‘D’)
def __init__(self, denom, suit):
if denom not in Card.legal_nums:
raise ValueError(“Bad #”)
if suit not in Card.legal_suits:
raise ValueError(“Bad suit”)
# could also reference them via self.
Gotchas
Consider this:
class C:
c = 3
def __init__(self):
print self.c
C.c = 33
print self.c
self.c = 77
print C.c
print self.c
c = C()
Output:
3
33
33
77
Download