预计阅读本页时间:-
Part VII, Exceptions and Tools
See Test Your Knowledge: Part VII Exercises in Chapter 35 for the exercises.
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
- try/except. My version of the oops function (file oops.py) follows. As for the noncoding questions, changing oops to raise a KeyError instead of an IndexError means that the try handler won’t catch the exception (it “percolates” to the top level and triggers Python’s default error message). The names KeyError and IndexError come from the outermost built-in names scope. Import builtins (__builtin__ in Python 2.6) and pass it as an argument to the dir function to see for yourself:
def oops():
raise IndexError()
def doomed():
try:
oops()
except IndexError:
print('caught an index error!')
else:
print('no error caught...')
if __name__ == '__main__': doomed()
% python oops.py
caught an index error! - Exception objects and lists. Here’s the way I extended this module for an exception of my own:
class MyError(Exception): pass
Like all class exceptions, the instance comes back as the extra data; the error message shows both the class (<...>) and its instance (Spam!). The instance must be inheriting both an __init__ and a __repr__ or __str__ from Python’s Exception class, or it would print like the class does. See Chapter 34 for details on how this works in built-in exception classes.
def oops():
raise MyError('Spam!')
def doomed():
try:
oops()
except IndexError:
print('caught an index error!')
except MyError as data:
print('caught error:', MyError, data)
else:
print('no error caught...')
if __name__ == '__main__':
doomed()
% python oops.py
caught error: <class '__main__.MyError'> Spam! - Error handling. Here’s one way to solve this one (file safe2.py). I did my tests in a file, rather than interactively, but the results are about the same.
import sys, traceback
def safe(entry, *args):
try:
entry(*args) # Catch everything else
except:
traceback.print_exc()
print('Got', sys.exc_info()[0], sys.exc_info()[1])
import oops
safe(oops.oops)
% python safe2.py
Traceback (innermost last):
File "safe2.py", line 5, in safe
entry(*args) # Catch everything else
File "oops.py", line 4, in oops
raise MyError, 'world'
hello: world
Got hello world - Here are a few examples for you to study as time allows; for more, see follow-up books and the Web:
# Find the largest Python source file in a single directory
import os, glob
dirname = r'C:\Python30\Lib'
allsizes = []
allpy = glob.glob(dirname + os.sep + '*.py')
for filename in allpy:
filesize = os.path.getsize(filename)
allsizes.append((filesize, filename))
allsizes.sort()
print(allsizes[:2])
print(allsizes[-2:])
# Find the largest Python source file in an entire directory tree
import sys, os, pprint
if sys.platform[:3] == 'win':
dirname = r'C:\Python30\Lib'
else:
dirname = '/usr/lib/python'
allsizes = []
for (thisDir, subsHere, filesHere) in os.walk(dirname):
for filename in filesHere:
if filename.endswith('.py'):
fullname = os.path.join(thisDir, filename)
fullsize = os.path.getsize(fullname)
allsizes.append((fullsize, fullname))
allsizes.sort()
pprint.pprint(allsizes[:2])
pprint.pprint(allsizes[-2:])
# Find the largest Python source file on the module import search path
import sys, os, pprint
visited = {}
allsizes = []
for srcdir in sys.path:
for (thisDir, subsHere, filesHere) in os.walk(srcdir):
thisDir = os.path.normpath(thisDir)
if thisDir.upper() in visited:
continue
else:
visited[thisDir.upper()] = True
for filename in filesHere:
if filename.endswith('.py'):
pypath = os.path.join(thisDir, filename)
try:
pysize = os.path.getsize(pypath)
except:
print('skipping', pypath)
allsizes.append((pysize, pypath))
allsizes.sort()
pprint.pprint(allsizes[:3])
pprint.pprint(allsizes[-3:])
# Sum columns in a text file separated by commas
filename = 'data.txt'
sums = {}
for line in open(filename):
cols = line.split(',')
nums = [int(col) for col in cols]
for (ix, num) in enumerate(nums):
sums[ix] = sums.get(ix, 0) + num
for key in sorted(sums):
print(key, '=', sums[key])
# Similar to prior, but using lists instead of dictionaries for sums
import sys
filename = sys.argv[1]
numcols = int(sys.argv[2])
totals = [0] * numcols
for line in open(filename):
cols = line.split(',')
nums = [int(x) for x in cols]
totals = [(x + y) for (x, y) in zip(totals, nums)]
print(totals)
# Test for regressions in the output of a set of scripts
import os
testscripts = [dict(script='test1.py', args=''), # Or glob script/args dir
dict(script='test2.py', args='spam')]
for testcase in testscripts:
commandline = '%(script)s %(args)s' % testcase
output = os.popen(commandline).read()
result = testcase['script'] + '.result'
if not os.path.exists(result):
open(result, 'w').write(output)
print('Created:', result)
else:
priorresult = open(result).read()
if output != priorresult:
print('FAILED:', testcase['script'])
print(output)
else:
print('Passed:', testcase['script'])
# Build GUI with tkinter (Tkinter in 2.6) with buttons that change color and grow
from tkinter import * # Use Tkinter in 2.6
import random
fontsize = 25
colors = ['red', 'green', 'blue', 'yellow', 'orange', 'white', 'cyan', 'purple']
def reply(text):
print(text)
popup = Toplevel()
color = random.choice(colors)
Label(popup, text='Popup', bg='black', fg=color).pack()
L.config(fg=color)
def timer():
L.config(fg=random.choice(colors))
win.after(250, timer)
def grow():
global fontsize
fontsize += 5
L.config(font=('arial', fontsize, 'italic'))
win.after(100, grow)
win = Tk()
L = Label(win, text='Spam',
font=('arial', fontsize, 'italic'), fg='yellow', bg='navy',
relief=RAISED)
L.pack(side=TOP, expand=YES, fill=BOTH)
Button(win, text='press', command=(lambda: reply('red'))).pack(side=BOTTOM,fill=X)
Button(win, text='timer', command=timer).pack(side=BOTTOM, fill=X)
Button(win, text='grow', command=grow).pack(side=BOTTOM, fill=X)
win.mainloop()
# Similar to prior, but use classes so each window has own state information
from tkinter import *
import random
class MyGui:
"""
A GUI with buttons that change color and make the label grow
"""
colors = ['blue', 'green', 'orange', 'red', 'brown', 'yellow']
def __init__(self, parent, title='popup'):
parent.title(title)
self.growing = False
self.fontsize = 10
self.lab = Label(parent, text='Gui1', fg='white', bg='navy')
self.lab.pack(expand=YES, fill=BOTH)
Button(parent, text='Spam', command=self.reply).pack(side=LEFT)
Button(parent, text='Grow', command=self.grow).pack(side=LEFT)
Button(parent, text='Stop', command=self.stop).pack(side=LEFT)
def reply(self):
"change the button's color at random on Spam presses"
self.fontsize += 5
color = random.choice(self.colors)
self.lab.config(bg=color,
font=('courier', self.fontsize, 'bold italic'))
def grow(self):
"start making the label grow on Grow presses"
self.growing = True
self.grower()
def grower(self):
if self.growing:
self.fontsize += 5
self.lab.config(font=('courier', self.fontsize, 'bold'))
self.lab.after(500, self.grower)
def stop(self):
"stop the button growing on Stop presses"
self.growing = False
class MySubGui(MyGui):
colors = ['black', 'purple'] # Customize to change color choices
MyGui(Tk(), 'main')
MyGui(Toplevel())
MySubGui(Toplevel())
mainloop()
# Email inbox scanning and maintenance utility
"""
scan pop email box, fetching just headers, allowing
deletions without downloading the complete message
"""
import poplib, getpass, sys
mailserver = 'your pop email server name here' # pop.rmi.net
mailuser = 'your pop email user name here' # brian
mailpasswd = getpass.getpass('Password for %s?' % mailserver)
print('Connecting...')
server = poplib.POP3(mailserver)
server.user(mailuser)
server.pass_(mailpasswd)
try:
print(server.getwelcome())
msgCount, mboxSize = server.stat()
print('There are', msgCount, 'mail messages, size ', mboxSize)
msginfo = server.list()
print(msginfo)
for i in range(msgCount):
msgnum = i+1
msgsize = msginfo[1][i].split()[1]
resp, hdrlines, octets = server.top(msgnum, 0) # Get hdrs only
print('-'*80)
print('[%d: octets=%d, size=%s]' % (msgnum, octets, msgsize))
for line in hdrlines: print(line)
if input('Print?') in ['y', 'Y']:
for line in server.retr(msgnum)[1]: print(line) # Get whole msg
if input('Delete?') in ['y', 'Y']:
print('deleting')
server.dele(msgnum) # Delete on srvr
else:
print('skipping')
finally:
server.quit() # Make sure we unlock mbox
input('Bye.') # Keep window up on Windows
# CGI server-side script to interact with a web browser
#!/usr/bin/python
import cgi
form = cgi.FieldStorage() # Parse form data
print("Content-type: text/html\n") # hdr plus blank line
print("<HTML>")
print("<title>Reply Page</title>") # HTML reply page
print("<BODY>")
if not 'user' in form:
print("<h1>Who are you?</h1>")
else:
print("<h1>Hello <i>%s</i>!</h1>" % cgi.escape(form['user'].value))
print("</BODY></HTML>")
# Database script to populate and query a MySql database
from MySQLdb import Connect
conn = Connect(host='localhost', user='root', passwd='darling')
curs = conn.cursor()
try:
curs.execute('drop database testpeopledb')
except:
pass # Did not exist
curs.execute('create database testpeopledb')
curs.execute('use testpeopledb')
curs.execute('create table people (name char(30), job char(10), pay int(4))')
curs.execute('insert people values (%s, %s, %s)', ('Bob', 'dev', 50000))
curs.execute('insert people values (%s, %s, %s)', ('Sue', 'dev', 60000))
curs.execute('insert people values (%s, %s, %s)', ('Ann', 'mgr', 40000))
curs.execute('select * from people')
for row in curs.fetchall():
print(row)
curs.execute('select * from people where name = %s', ('Bob',))
print(curs.description)
colnames = [desc[0] for desc in curs.description]
while True:
print('-' * 30)
row = curs.fetchone()
if not row: break
for (name, value) in zip(colnames, row):
print('%s => %s' % (name, value))
conn.commit() # Save inserted records
# Database script to populate a shelve with Python objects
# see also Chapter 27 shelve and Chapter 30 pickle examples
rec1 = {'name': {'first': 'Bob', 'last': 'Smith'},
'job': ['dev', 'mgr'],
'age': 40.5}
rec2 = {'name': {'first': 'Sue', 'last': 'Jones'},
'job': ['mgr'],
'age': 35.0}
import shelve
db = shelve.open('dbfile')
db['bob'] = rec1
db['sue'] = rec2
db.close()
# Database script to print and update shelve created in prior script
import shelve
db = shelve.open('dbfile')
for key in db:
print(key, '=>', db[key])
bob = db['bob']
bob['age'] += 1
db['bob'] = bob
db.close()