Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 625 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
625
Dung lượng
3,29 MB
Nội dung
I l@ve RuBoard Learning Python [A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X] [Z] M Macintosh Python distributions mail servers mailing lists makepy.py program See : documentation manuals map function mapping max function McFarlane, Greg Medusa See : in operator membership test metaprograms methods bound, unbound names available Microsoft's Common Object Model (COM) , 2nd min function mixed types, expression operators mixin classes module files defined names module gotchas from statement import, from statements recursive imports reload statement order modules , 2nd , 3rd classes, versus compilation model creating data hiding convention defined design concepts import, reload importing metaprograms name and main namespaces packages PYTHONPATH variable and roles of search path shipping options using modulus operator mul method multiple inheritance classes mixin order multiple-target assignments multiplication operator mutability , 2nd , 3rd , 4th I l@ve RuBoard Copyright Table of Contents Index Full Description About the Author Reviews Colophon Examples Reader reviews Errata Learning Python Mark Lutz David Ascher Publisher: O'Reilly First Edition April 1999 ISBN: 1-56592-464-9, 384 pages Learning Python is an introduction to the increasingly popular Python programming languagean interpreted, interactive, object-oriented, and portable scripting language This book thoroughly introduces the elements of Python: types, operators, statements, classes, functions, modules, and exceptions It also demonstrates how to perform common programming tasks and write real applications I l@ve RuBoard Learning Python [A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X] [Z] A abs function add method , 2nd addition operator Alice Amiga Python distributions & (bitwise and) operator and operator , 2nd append method , 2nd , 3rd apply function argument passing arbitrary-argument set functions (example) assignment keywords, defaults (example) matching modes ordering rules return statement arguments argv attribute (sys module) , 2nd assert statement assignment references versus copies assignment statements forms implicit object references variable name rules * (multiplication) operator , 2nd automated dial-out script I l@ve RuBoard I l@ve RuBoard Learning Python [A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X] [Z] B backslash != comparison operator BeOS Python distribution binary files binary Python distribution bitwise operations bitwise operators blank lines block delimiters books for further reading Boolean operators bound instance methods {} (braces) [] (brackets) , 2nd , 3rd break statement built-in functions , 2nd built-in modules binary files cgi module debugging Internet data processing Internet protocols pickle profiling string constants string functions time module Tkinter urllib urlparse built-in object types , 2nd builtins namespace bytecode , 2nd I l@ve RuBoard I l@ve RuBoard Learning Python [A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X] [Z] C C source-code Python distribution C++ language , 2nd ^ (bitwise exclusive or) operator case-independent sort case sensitivity, names cgi module CGI scripts GUI programs vs chr function , 2nd class attributes class exceptions class gotchas changing attributes class function attributes methods, classes, nested scopes multiple inheritance order class methods, using (example) class statement class attributes default behavior classes add method , 2nd built-in objects, extending designing with OOP documentation strings generic object factories getattr method getitem method inheritance init constructor , 2nd , 3rd instance objects modules, versus mul method multiple instance objects name mangling namespace rules OOP (example) operator overloading , 2nd persistence reasons for repr method subclasses superclasses close function Cmd class how works interactive functionality cmp function code C, Python and column 1 modules reuse coding gotchas def doomed(): try: oops() except IndexError: print 'caught an index error!' except MyError, data: print 'caught error:', MyError, data else: print 'no error caught ' if name == ' main ': doomed() % python oops.py caught error: hello world Error handling Finally, here's one way to solve this one; we decided to do our tests in a file, rather than interactively, but the results are about the same % cat safe2.py import sys, traceback def safe(entry, *args): try: apply(entry, args) # catch everythin except: traceback.print_exc() print 'Got', sys.exc_type, sys.exc_value import oops safe(oops.oops) % python safe2.py Traceback (innermost last): File "safe2.py", line 5, in safe apply(entry, args) # catch everythin File "oops.py", line 4, in oops raise MyError, 'world' hello: world Got hello world C.8 Chapter 8 Describing a directory There are several solutions to this exercise, naturally One simple solution is: import os, sys, stat def describedir(start): def describedir_helper(arg, dirname, files): """ Helper function for describing directories """ print "Directory %s has files:" % dirname for file in files: # find the full path to the file (directory + fi fullname = os.path.join(dirname, file) if os.path.isdir(fullname): # if it's a directory, say so; no need to fi print ' '+ file + ' (subdir)' else: # find out the size, and print the info size = os.stat(fullname)[stat.ST_SIZE] print ' '+file+' size=' + `size` # Start the 'walk' os.path.walk(start, describedir_helper, None) which uses the walk function in the os.path module, and works just fine: >>> import describedir >>> describedir.describedir2('testdir') Directory testdir has files: describedir.py size=939 subdir1 (subdir) subdir2 (subdir) Directory testdir\subdir1 has files: makezeros.py size=125 subdir3 (subdir) Directory testdir\subdir1\subdir3 has files: Directory testdir\subdir2 has files: Note that you could have found the size of the files by doing len(open(fullname, 'rb').read()), but this works only when you have read access to all the files and is quite inefficient The stat call in the os module gives out all kinds of useful information in a tuple, and the stat module defines some names that make it unnecessary to remember the order of the elements in that tuple See the Library Reference for details Modifying the prompt The key to this exercise is to remember that the ps1 and ps2 attributes of the sys module can be anything, including a class instance with a repr or _ _str method For example: import sys, os class MyPrompt: def init (self, subprompt='>>> '): self.lineno = 0 self.subprompt = subprompt def repr (self): self.lineno = self.lineno + 1 return os.getcwd()+'|%d'%(self.lineno)+self.subpromp sys.ps1 = MyPrompt() sys.ps2 = MyPrompt(' ') This code works as shown (use the -i option of the Python interpreter to make sure your program starts right away): h:\David\book> python -i modifyprompt.py h:\David\book|1>>> x = 3 h:\David\book|2>>> y = 3 h:\David\book|3>>> def foo(): h:\David\book|3 x = 3 # the secondary pr h:\David\book|3 h:\David\book|4>>> import os h:\David\book|5>>> os.chdir(' ') h:\David|6>>> # note the prompt Avoiding regular expressions This program is long and tedious, but not especially complicated See if you can understand how it works Whether this is easier for you than regular expressions depends on many factors, such as your familiarity with regular expressions and your comfort with the functions in the string module Use whichever type of programming works for you import string file = open('pepper.txt') text = file.read() paragraphs = string.split(text, '\n\n') def find_indices_for(big, small): indices = [] cum = 0 while 1: index = string.find(big, small) if index == -1: return indices indices.append(index+cum) big = big[index+len(small):] cum = cum + index + len(small) def fix_paragraphs_with_word(paragraphs, word): lenword = len(word) for par_no in range(len(paragraphs)): p = paragraphs[par_no] wordpositions = find_indices_for(p, word) if wordpositions == []: return for start in wordpositions: # look for 'pepper' ahead indexpepper = string.find(p, 'pepper') if indexpepper == -1: return -1 if string.strip(p[start:indexpepper]) != '': # something other than whitespace in between continue where = indexpepper+len('pepper') if p[where:where+len('corn')] == 'corn': # it's immediately followed by 'corn'! continue if string.find(p, 'salad') < where: # it's not followed by 'salad' continue # Finally! we get to do a change! p = p[:start] + 'bell' + p[start+lenword:] paragraphs[par_no] = p # change mutable fix_paragraphs_with_word(paragraphs, 'red') fix_paragraphs_with_word(paragraphs, 'green') for paragraph in paragraphs: print paragraph+'\n' We won't repeat the output here; it's the same as that of the regular expression solution Wrapping a text file with a class This one is surprisingly easy, if you understand classes and the split function in the string module The following is a version that has one little twist over and beyond what we asked for: import string class FileStrings: def init (self, filename=None, data=None): if data == None: self.data = open(filename).read() else: self.data = data self.paragraphs = string.split(self.data, '\n\n') self.lines = string.split(self.data, '\n') self.words = string.split(self.data) def repr (self): return self.data def paragraph(self, index): return FileStrings(data=self.paragraphs[index]) def line(self, index): return FileStrings(data=self.lines[index]) def word(self, index): return self.words[index] This solution, when applied to the file pepper.txt, gives: >>> from FileStrings import FileStrings >>> bigtext = FileStrings('pepper.txt') >>> print bigtext.paragraph(0) This is a paragraph that mentions bell peppers multiple time one, here is a red Pepper and dried tomato salad recipe I to use green peppers in my salads as much because they have flavor >>> print bigtext.line(0) This is a paragraph that mentions bell peppers multiple time >>> print bigtext.line(-4) aren't peppers, they're chilies, but would you rather have a >>> print bigtext.word(-4) botanist How does it work? The constructor simply reads all the file into a big string (the instance attribute data) and then splits it according to the various criteria, keeping the results of the splits in instance attributes that are lists of strings When returning from one of the accessor methods, the data itself is wrapped in a FileStrings object This isn't required by the assignment, but it's nice because it means you can chain the operations, so that to find out what the last word of the third line of the third paragraph is, you can just write: >>> print bigtext.paragraph(2).line(2).word(-1) 'cook' C.9 Chapter 9 Redirecting stdout This is simple: all you have to do is to replace the first line with: import fileinput, sys, string # no change here sys.stdout = open(sys.argv[-1], 'w') # open the outpu del sys.argv[-1] # we've dealt wi # continue as be Writing a simple shell Mostly, the following script, which implements the Unix set of commands (well, some of them) should be selfexplanatory Note that we've only put a "help" message for the ls command, but there should be one for all the other commands as well: import cmd, os, string, sys, shutil class UnixShell(cmd.Cmd): def do_EOF(self, line): """ The do_EOF command is called when the user press or Ctrl-Z (PC) """ sys.exit() def help_ls(self): print "ls : list the contents of the spec print " (current directory used by de def do_ls(self, line): # 'ls' by itself means 'list current directory' if line == '': dirs = [os.curdir] else: dirs = string.split(line) for dirname in dirs: print 'Listing of %s:' % dirname print string.join(os.listdir(dirname), '\n') def do_cd(self, dirname): # 'cd' by itself means 'go home' if dirname == '': dirname = os.environ['HOME'] os.chdir(dirname) def do_mkdir(self, dirname): os.mkdir(dirname) def do_cp(self, line): words = string.split(line) sourcefiles,target = words[:-1], words[-1] # target for sourcefile in sourcefiles: shutil.copy(sourcefile, target) def do_mv(self, line): source, target = string.split(line) os.rename(source, target) def do_rm(self, line): map(os.remove, string.split(line)) class DirectoryPrompt: def repr (self): return os.getcwd()+'> ' cmd.PROMPT = DirectoryPrompt() shell = UnixShell() shell.cmdloop() Note that we've reused the same trick as in Exercise 2 of Chapter 8 to have a prompt that adjusts with the current directory, combined with the trick of modifying the attribute PROMPT in the cmd module itself Of course those weren't part of the assignment, but it's hard to just limit oneself to a simple thing when a full-featured one will do It works, too! h:\David\book> python -i shell.py h:\David\book> cd /tmp h:\David\tmp> ls Listing of : api ERREUR.DOC ext giant_~1.jpg icons index.html lib pythlp.hhc pythlp.hhk ref tut h:\David\tmp> cd h:\David> cd tmp h:\David\tmp> cp index.html backup.html h:\David\tmp> rm backup.html h:\David\tmp> ^Z Of course, to be truly useful, this script needs a lot of error checking and many more features, all of which is left, as math textbooks say, as an exercise for the reader Understanding map, reduce and filter The following functions do as much of the job of map, reduce, and filter as we've told you about; if you're curious about the differences, check the reference manual def map2(function, sequence): if function is None: return list(sequence) retvals = [] for element in sequence: retvals.append(function(element)) return retvals def reduce2(function, sequence): arg1 = function(sequence[0]) for arg2 in sequence[1:]: arg1 = function(arg1, arg2) return arg1 def filter2(function, sequence): retvals = [] for element in sequence: if (function is None and element) or function(elemen retvals.append(element) return retvals C.10 Chapter 10 Faking the Web What you need to do is to create instances of a class that has the fieldnames attribute and appropriate instance variables One possible solution is: class FormData: def init (self, dict): for k, v in dict.items(): setattr(self, k, v) class FeedbackData(FormData): """ A FormData generated by the comment.html form """ fieldnames = ('name', 'address', 'email', 'type', 'text' def repr (self): return "%(type)s from %(name)s on %(time)s" % vars(s fake_entries = [ {'name': "John Doe", 'address': '500 Main St., SF CA 94133', 'email': 'john@sf.org', 'type': 'comment', 'text': 'Great toothpaste!'}, {'name': "Suzy Doe", 'address': '500 Main St., SF CA 94133', 'email': 'suzy@sf.org', 'type': 'complaint', 'text': "It doesn't taste good when I kiss John!"}, ] DIRECTORY = r'C:\complaintdir' if name == ' main ': import tempfile, pickle, time tempfile.tempdir = DIRECTORY for fake_entry in fake_entries: data = FeedbackData(fake_entry) filename = tempfile.mktemp() data.time = time.asctime(time.localtime(time.time()) pickle.dump(data, open(filename, 'w')) As you can see, the only thing you really had to change was the way the constructor for FormData works, since it has to do the setting of attributes from a dictionary as opposed to a FieldStorage object Cleaning up There are many ways to deal with this problem One easy one is to modify the formletter.py program to keep a list of the filenames that it has already processed (in a pickled file, of course!) This can be done by modifying the if main == ' name ' test to read something like this (new lines are in bold): if name == ' main ': import os, pickle CACHEFILE = 'C:\cache.pik' from feedback import DIRECTORY#, FormData, FeedbackData if os.path.exists(CACHEFILE): processed_files = pickle.load(open(CACHEFILE)) else: processed_files = [] for filename in os.listdir(DIRECTORY): if filename in processed_files: continue # skip thi processed_files.append(filename) data = pickle.load(open(os.path.join(DIRECTORY, file if data.type == 'complaint': print "Printing letter for %(name)s." % vars(dat print_formletter(data) else: print "Got comment from %(name)s, skipping print vars(data) pickle.dump(processed_file, open(CACHEFILE, 'w') As you can tell, you simply load a list of the previous filenames if it exists (and use an empty list otherwise) and compare the filenames with entries in the list to determine which to skip If you don't skip one, it needs to be added to the list Finally, at program exit, pickle the new list Adding parametric plotting to grapher.py This exercise is quite simple, as all that's needed is to change the drawing code in the Chart class Specifically, the code between xmin, xmax = 0, N1 and graphics.fillPolygon( ) should be placed in an if test, so that the new code reads: if not hasattr(self.data[0], ' len '): # it's probably a xmin, xmax = 0, N-1 # code from existing graphics.fillPolygon(xs, ys, len(xs)) elif len(self.data[0]) == 2: # we'll only deal xmin = reduce(min, map(lambda d: d[0], self.data)) xmax = reduce(max, map(lambda d: d[0], self.data)) ymin = reduce(min, map(lambda d: d[1], self.data)) ymax = reduce(max, map(lambda d: d[1], self.data)) zero_y = y_offset - int(-ymin/(ymax-ymin)*height) zero_x = x_offset + int(-xmin/(xmax-xmin)*width) for i in range(N): xs[i] = x_offset + int((self.data[i][0]-xmin)/(xm ys[i] = y_offset - int((self.data[i][1]-ymin)/(ym graphics.color = self.color if self.style == "Line": graphics.drawPolyline(xs, ys, len(xs)) else: xs.append(xs[0]); ys.append(ys[0]) graphics.fillPolygon(xs, ys, len(xs)) Colophon Our look is the result of reader comments, our own experimentation, and feedback from distribution channels Distinctive covers complement our distinctive approach to technical topics, breathing personality and life into potentially dry subjects The animal on the cover of Learning Python is a wood rat ( Neotoma, family Muridae) The wood rat lives in a wide range of living conditions (mostly rocky, scrub, and desert areas) over much of North and Central America, generally at some distance from humans, though they occasionally damage some crops They are good climbers, nesting in trees or bushes up to six meters off the ground; some species burrow underground or in rock crevices or inhabit other species' abandoned holes These greyish-beige, medium-sized rodents are the original pack rats: they carry anything and everything into their homes, whether or not it's needed, and are especially attracted to shiny objects such as tin cans, glass, and silverware Mary Anne Weeks Mayo was the production editor and copyeditor of Learning Python; Sheryl Avruch was the production manager; Jane Ellin, Melanie Wang, and Clairemarie Fisher O'Leary provided quality control Robert Romano created the illustrations using Adobe Photoshop 4 and Macromedia FreeHand 7 Mike Sierra provided FrameMaker technical support Ruth Rautenberg wrote the index, with input from Seth Maislin Edie Freedman designed the cover of this book, using a 19th-century engraving from the Dover Pictorial Archive The cover layout was produced with Quark XPress 3.32 using the ITC Garamond font The inside layout was designed by Alicia Cech and implemented in FrameMaker 5.5 by Mike Sierra The text and heading fonts are ITC Garamond Light and Garamond Book This colophon was written by Nancy Kotary ... Errata Learning Python Mark Lutz David Ascher Publisher: O'Reilly First Edition April 1999 ISBN: 1-56592-464-9, 384 pages Learning Python is an introduction to the increasingly popular Python. .. I l@ve RuBoard Learning Python [A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X] [Z] B backslash != comparison operator BeOS Python distribution binary files binary Python distribution... documentation strings DOS/Windows 3.1 Python distributions downloading Python distributions downloading web pages dynamic typing , 2nd , 3rd I l@ve RuBoard I l@ve RuBoard Learning Python [A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][X]