[Note from the future: this page was restyled in 2018 for mobile, but its original content was left intact (even the silly bits). Early days to be sure, but most of it is still surprisingly relevant two decades later. The talk announcement is still online here, while it lasts.]
This page contains HTML renditions of slides from an introductory talk on Python I've given in the past. Some of it has been updated, but not since its last change date: 5/23/97.
Much of this material comes from the book "Programming Python". Since the pages here lack the narrative you'd get in a talk (or the book), I'm not sure how useful this is as an intro to Python; on the other hand, it's free :-).
Please send comments about this page to lutz@learning-python.com.
Also see the appendix page for supplemental material. Some of it is specific to a company I've worked for, but it also includes some general Python information not listed above:
Update: also see the new integration examples page for more Python/C integration examples.
"And now, for something completely different..." Mark Lutz March 1997
Seen on comp.lang.python...
"python, (Gr. Myth. An enormous serpent that lurked in the cave of Mount Parnassus and was slain by Apollo) 1. any of a genus of large, non-poisonous snakes of Asia, Africa and Australia that crush their prey to death. 2. popularly, any large snake that crushes its prey. 3. totally awesome, bitchin' language invented by that rad computer geek Guido van Rossum that will someday crush the $'s out of certain *other* so-called VHLLs ;-)"
HTML file <HEAD> <TITLE>Grail Applet Test Page</TITLE> </HEAD> <BODY> <H1>Test an Applet Here!</H1> Click this button! <APP CLASS=Question> </BODY> file: Question.py # Python applet file: Question.py # in the same location (URL) as the html file # that references it; adds widgets to browser; from Tkinter import * class Question: # run by grail? def __init__(self, master): # master=browser self.button = Button(master, bitmap='question', command=self.action) self.button.pack() def action(self): if self.button['bitmap'] == 'question': self.button.config(bitmap='questhead') else: self.button.config(bitmap='question') if __name__ == '__main__': root = Tk() # run stand-alone? button = Question(root) # master=Tk: top-level root.mainloop()
file: brian.py #!/usr/local/bin/python print 'The Bright Side of Life...' % brian.py
% python spam.py -i eggs -o bacon
% python >>> print 'Hello world!' Hello world! >>> lumberjack = "okay"
Py_Initialize(); PyRun_SimpleString("x = brave + sir + robin");
Notes: on UNIX, the environment variable PYTHONPATH should list all source directories you want to import modules from. Program start techniques and configuration details differ on Windows and Macintosh platforms; see package documentation.
Numbers: 3.1415 Strings: 'spam' Lists: [1, [2, 'three']] Dictionaries: {'food':'spam', 'taste':'yum'} Tuples: (1,'spam', 4, 'U') Files: open('temp', 'r').read()
1234 normal integers (C long's) 99999999L long integers (unlimited size) 1.23, 3.14e-10 floating-point (C double's) 0177, 0x9ff octal and hex constants
% python >>> a = 3 >>> b = 4 >>> b / 2 + a 5 >>> b / (2.0 + a) 0.8 >>> 9999999999999999999999999999 + 1 OverflowError: integer literal too large >>> 9999999999999999999999999999L + 1 10000000000000000000000000000L
s1 = '' empty strings s2 = "spam's" double quotes s2[i], s2[i:j] indexing, slicing s1 + s2, s2 * 3 concatenate, repeat "a %s parrot" % 'dead' string formatting block = """...""" triple-quoted blocks
% python >>> 'abc' + 'def' 'abcdef' >>> 'Ni!' * 4 # like "Ni!" + "Ni!" + ... 'Ni!Ni!Ni!Ni!' >>> S = 'spam' >>> S[0], S[-2] # same as: S[len(S)-2] ('s', 'a') >>> S[:-1], S[1:] ('spa', 'pam') >>> 'That is %d %s bird!' % (1, 'dead') That is 1 dead bird!
L1 = [] an empty list L2 = [0, 1, 2, 3] 4-items: indexes 0..3 ['abc', ['def', 'ghi']] nested sublists L2[i], L2[i:j] indexing, slicing L1 + L2, L2 * 3 concatenate, repeat L2.append(newvalue) growing: methods del L2[k], L2[i:j] = [] shrinking L2[i:j] = [1,2,3] slice assignment range(4), xrange(0, 4) make integer lists
% python >>> [1, 2, 3] + [4, 5, 6] [1, 2, 3, 4, 5, 6] >>> ['Ni!'] * 4 ['Ni!', 'Ni!', 'Ni!', 'Ni!'] >>> L = ['spam', 'Spam', 'SPAM!'] >>> L[2] 'SPAM!' >>> L[1] = 'eggs' >>> for x in L: print x, ... spam eggs SPAM!
d1 = {} empty d2 = {'spam': 2, 'ham': 1, 'eggs': 3} 3-items d3 = {'pork': {'ham': 1, 'brats': 2}} nesting d2['eggs'], d3['pork']['ham'] indexing d2.has_key('eggs'), d2.keys() methods
% python >>> table ={'Perl': 'Larry Wall', ... 'Tcl': 'John Ousterhout', ... 'Python': 'Guido van Rossum' } ... >>> language = 'Python' >>> creator = table[language] 'Guido van Rossum'
() an empty tuple t1 = (0,) a one-item tuple t2 = (0, 1, 2, 3) 4-item tuple t3 = ('abc', ('def', 'ghi')) nested tuples t1[i], t1[i:j] index, slice t1 + t2, t2 * 3 concatenate, repeat
o = open("/tmp/spam", 'w') output file i = open('data', 'r') input file i.read(), i.readline(), i.read(1) file,line,char o.write(s), o.writelines(l) string,lines o.close() or when free'd
In Python, everything is an object type.
L = ['abc', [(1,2), ([3], 4)], 5]
spam = 'SPAM' basic form spam, ham = 'yum', 'YUM' tuple assignment [spam, ham] = ['yum', 'YUM'] list assignment spam = ham = 'lunch' multi-target
spam(egs, ham) function calls spam.ham(eggs) method calls spam print interactive spam < ham and ham != eggs compound expr's spam < ham < eggs range tests
print spam, ham print objects to sys.stdout print spam, ham, don't add linefeed
>>> x = 'killer rabbit' >>> if x == 'bunny': ... print 'hello little bunny' ... elif x == 'bugs': ... print "what's up doc?" ... else: ... print 'Run away! Run away!...' ... Run away! Run away!...
while 1: print 'Type Ctrl-C to stop me!' The loop "else"... x = y / 2 while x > 1: if y % x == 0: # remainder print y, 'has factor', x break # skip else x = x-1 else: # normal exit print y, 'is prime'
>>> for x in ["spam", "eggs", "spam"]: ... print x, ... spam eggs spam Counter loops... >>> range(5) [0, 1, 2, 3, 4] >>> for i in xrange(len(X)): print X[i] >>> for i in range(5): print 'A shrubbery!' ... A shrubbery! A shrubbery! A shrubbery! A shrubbery! A shrubbery!
Modules: code/data packages Classes: new objects Functions: procedural units C modules: optimization, integration Exceptions: errors and special cases
Modules contain Statements that process Objects
def intersect(seq1, seq2): res = [] # start empty for x in seq1: # scan seq1 if x in seq2: # common item? res.append(x) # add to end return res >>> s1 = "SPAM" >>> s2 = "SCAM" >>> intersect(s1, s2) # strings ['S', 'A', 'M'] >>> intersect([1, 2, 3], (1, 4)) # mixed types [1]
file: hello.py def printer(x): print x % python >>> import hello >>> hello.printer('Hello world!') Hello world! >>> from hello import printer >>> printer('Hello world!') >>> from hello import * >>> printer('Hello world!')
class FirstClass: # class def printer(self, text): # method print text x = FirstClass() x.printer('Hello world!') class SecondClass(FirstClass): # subclass def __init__(self, value): # constructor self.name = value def printname(self): self.printer(self.name) # inherited x = SecondClass('Hello world!') x.printname()
class Counter: def __init__(self, start): # on Counter() self.data = start def __call__(self): # on x() self.data = self.data + 1 return self.data def __add__(self, y): # on x + y return Counter(self.data + y) def __repr__(self): # on print return `self.data` if __name__ == "__main__": x = Counter(2) # self-test x = x + 4 print x # 6 c1 = Counter(10) c2 = Counter(24) print c1(), c2(), c1(), c2() # 11, 25, 12, 26
Builtin exceptions... def kaboom(list, n): print list[n] # trigger IndexError try: kaboom([0, 1, 2], 3) except IndexError: print 'Hello world!' # catch exception here User-defined exceptions... MyError = "my error" def stuff(file): raise MyError file = open('data', 'r') # open a file try: stuff(file) # raises exception finally: file.close() # always close file
>>> import sys >>> sys.path ['.', '/usr/local/lib/python', ... ] >>> sys.platform 'sunos4'
>>> import os >>> os.environ['USER'] 'mlutz' >>> listing = os.popen("ls *.py").readlines() >>> for name in listing: print name, ... cheader1.py finder1.py summer.py >>> for name in listing: os.system("vi " + name) ... >>> os.listdir(".") ['summer.out', 'summer.py', 'table1.txt', ... ]
>>> import glob, string, os >>> glob.glob("*.py") ['cheader1.py', 'finder1.py', 'summer.py'] >>> for name in glob.glob("*.py"): ... os.rename(name, string.upper(name)) ... >>> glob.glob("*.PY") ['FINDER1.PY', 'SUMMER.PY', 'CHEADER1.PY']
% cat play.py #!/usr/local/bin/python import sys print sys.argv sys.stdout.write("ta da!\n") % play.py -x -i spammify ['play.py', '-x', '-i', 'spammify'] ta da!
A zoo-animal hiearchy in Python
file: zoo.py class Animal: def reply(self): self.speak() def speak(self): print 'spam' class Mammal(Animal): def speak(self): print 'huh?' class Cat(Mammal): def speak(self): print 'meow' class Dog(Mammal): def speak(self): print 'bark' class Primate(Mammal): def speak(self): print 'Hello world!' class Hacker(Primate): pass % python >>> from zoo import Cat, Hacker >>> spot = Cat() >>> spot.reply() meow >>> data = Hacker() >>> data.reply() Hello world!
The dead-parrot skit in Python
file: parrot.py class Actor: def line(self): print self.name + ':', `self.says()` class Customer(Actor): name = 'customer' def says(self): return "that's one ex-bird!" class Clerk(Actor): name = 'clerk' def says(self): return "no it isn't..." class Parrot(Actor): name = 'parrot' def says(self): return None class Scene: def __init__(self): self.clerk = Clerk() # embed some instances self.customer = Customer() # Scene is a composite self.subject = Parrot() def action(self): self.customer.line() # delegate to embedded self.clerk.line() self.subject.line() % python >>> import parrot >>> parrot.Scene().action() customer: "that's one ex-bird!" clerk: "no it isn't..." parrot: None
def echo(message): print message x = echo x('Hello world!') def indirect(func, arg): func(arg) indirect(echo, 'Hello world!') schedule = [ (echo, 'Hello!'), (echo, 'Ni!') ] for (func, arg) in schedule: apply(func, (arg,))
file: scanfile.py def scanner(name, function): file = open(name, 'r') # create file for line in file.readlines(): function(line) # call function file.close() file: commands.py import string from scanfile import scanner def processLine(line): print string.upper(line) scanner("data.txt", processLine) # start scanner
def factory(aClass, *args): # varargs tuple return apply(aClass, args) # call aClass class Spam: def doit(self, message): print message class Person: def __init__(self, name, job): self.name = name self.job = job object1 = factory(Spam) object2 = factory(Person, "Guido", "guru")
x = object1.doit # bound method object x('hello world') # instance is implied t = Spam.doit # unbound method object t(object1, 'howdy') # pass in instance
file: fixer.py editor = 'vi' # your editor's name def python(cmd): import __main__ namespace = __main__.__dict__ exec cmd in namespace, namespace def edit(filename): import os os.system(editor + ' ' + filename) def fix(modname): import sys # edit,(re)load edit(modname + '.py') if modname in sys.modules.keys(): python('reload(' + modname + ')') else: python('import ' + modname) % python >>> from fixer import fix >>> fix("spam") # browse/edit and import by string name >>> spam.function() # spam was imported in __main__ >>> fix("spam") # edit and reload() by string name >>> spam.function() # test new version of function
[See the appendix for examples]
% cat packer.py #!/usr/local/bin/python import sys # load the system module marker = '::::::' for name in sys.argv[1:]: # for all command-line args input = open(name, 'r') # open the next input file print marker + name # write a separator line print input.read(), # write the file's contents % packer.py spam.txt eggs.txt toast.txt > packed.txt
% cat packapp.py #!/usr/local/bin/python from apptools import StreamApp # get the superclass from textpack import marker # get marker constant class PackApp(StreamApp): # define a subclass def start(self): # define some methods if not self.args: self.exit('packapp.py [-o file]? src src...') def help(self): StreamApp.help(self) # superclass args print '<file> <file>...' # then show my args def run(self): for name in self.restargs(): try: self.message('packing: ' + name) self.pack_file(name) except: self.exit('error processing: ' + name) def pack_file(self, name): self.setInput(name) self.write(marker + name + '\n') while 1: line = self.readline() # read next line if not line: break # until eof self.write(line) # copy to output if __name__ == '__main__': PackApp().main() # script? % packapp.py -o packed.txt spam.txt eggs.txt toast.txt
file: hello #!/usr/local/bin/python from Tkinter import * # get widget classes class Hello(Frame): # container subclass def __init__(self, parent=None): Frame.__init__(self, parent) # do superclass init self.pack() self.make_widgets() def make_widgets(self): widget = Button(self, text='Hello world', command = self.onPress) widget.pack(side=LEFT) def onPress(self): print "Hi." if __name__ == '__main__': Hello().mainloop() % hello
file: person.py # a person object: fields + behavior # class defined at outer level of file class Person: def __init__(self, name = '', job = '', pay = 0): self.name = name self.job = job self.pay = pay # real instance data def tax(self): return self.pay * 0.25 # computed on demand def info(self): return self.name, self.job, self.pay, self.tax() % python >>>jerry = Person('jerry', 'dentist') >>>bob = Person('bob', 'psychologist', 70000) >>>emily = Person('emily', 'teacher', 40000) ... >>>import shelve >>>dbase = shelve.open('cast') # open a new dbm file >>>for obj in (bob, emily, jerry): # put objs in a shelve >>> dbase[obj.name] = obj ... >>>import shelve >>>dbase = shelve.open('cast') # reopen shelve file >>>print dbase['bob'].info() # fetch 'bob' object
file: inter.py def intersect(list1, list2): res = [] # start with an empty list for x in list1: # scan the first list if x in list2: res.append(x) # add common items to end return res def union(list1, list2): res = map(None, list1) # make a copy of list1 for x in list2: # add new items in list2 if not x in res: res.append(x) return res % python >>> from inter import * >>> s1 = "SPAM" >>> s2 = "SCAM" >>> intersect(s1, s2), union(s1, s2) # strings (['S', 'A', 'M'], ['S', 'P', 'A', 'M', 'C']) >>> intersect([1,2,3], (1,4)) # mixed types [1] >>> union([1,2,3], (1,4)) [1, 2, 3, 4]
file: set.py class Set: def __init__(self, value = []): # constructor self.data = [] # manages a list self.concat(value) def intersect(self, other): # other is a sequence res = [] # self is the subject for x in self.data: if x in other: res.append(x) return Set(res) # return a new Set def union(self, other): res = self.data[:] # copy of my list for x in other: if not x in res: res.append(x) return Set(res) def concat(self, value): # value: list, Set... for x in value: # removes duplicates if not x in self.data: self.data.append(x) def __len__(self): return len(self.data) def __getitem__(self, key): return self.data[key] def __and__(self, other): return self.intersect(other) def __or__(self, other): return self.union(other) def __repr__(self): return 'Set:' + `self.data` % python >>> from set import Set >>> x = Set([1,2,3,4]) # __init__ >>> y = Set([3,4,5]) >>> x & y, x | y # __and__,__or__,__repr__ (Set:[3, 4], Set:[1, 2, 3, 4, 5]) >>> z = Set("hello") # set of strings >>> z[0] # __getitem__ 'h' >>> z & "mello", z | "mello" (Set:['e', 'l', 'o'], Set:['h', 'e', 'l', 'o', 'm'])
file: inter2.py def intersect(*args): res = [] for x in args[0]: # scan first list for other in args[1:]: # for all other args if x not in other: break # this in each one? else: res.append(x) # add items to end return res def union(*args): res = [] for seq in args: # for all args for x in seq: # for all nodes if not x in res: res.append(x) # add items to result return res % python >>> from inter2 import * >>> s1, s2, s3 = "SPAM", "SCAM", "SLAM" >>> intersect(s1, s2), union(s1, s2) # 2 operands (['S', 'A', 'M'], ['S', 'P', 'A', 'M', 'C']) >>> intersect([1,2,3], (1,4)) [1] >>> intersect(s1, s2, s3) # 3 operands ['S', 'A', 'M'] >>> union(s1, s2, s3) ['S', 'P', 'A', 'M', 'C', 'L']
#!/usr/local/bin/python ############################################### # Usage: % sousa.py # Fetch and play the Monty Python theme song. ############################################### import os, sys from ftplib import FTP # socket-based ftp tools from posixpath import exists # file existence test sample = 'sousa.au' filter = {'sunos5': '/usr/bin/audioplay', 'linux1': '', 'sunos4': '/usr/demo/SOUND/play'} helpmsg = """ Sorry: can't find an audio filter for your system! Add an entry to the script's "filter" dictionary for your system's audio command, or ftp and play manually. """ # check the filter if (filter.has_key(sys.platform) and exists(filter[sys.platform])): print 'Working...' else: print helpmsg sys.exit(1) # ftp the audio file if not exists(sample): theme = open(sample, 'w') ftp = FTP('ftp.python.org') # connect to ftp site ftp.login() # use anonymous login ftp.cwd('pub/python/misc') ftp.retrbinary('RETR ' + sample, theme.write, 1024) ftp.quit() theme.close() # send it to audio device theme = open(sample, 'r') audio = os.popen(filter[sys.platform], 'w') # spawn tool audio.write(theme.read()) # to stdin
file: sockserver.py # Echo server program from socket import * HOST = '' # the local host PORT = 50007 # non-privileged server s = socket(AF_INET, SOCK_STREAM) s.bind(HOST, PORT) s.listen(1) conn, addr = s.accept() print 'Connected by', addr while 1: data = conn.recv(1024) if not data: break conn.send(data) conn.close() file: sockclient.py # Echo client program from socket import * HOST = 'daring.cwi.nl' # the remote host PORT = 50007 # the port used by server s = socket(AF_INET, SOCK_STREAM) s.connect(HOST, PORT) s.send('Hello, world') data = s.recv(1024) s.close() print 'Received', `data`
file: cheader1.py #! /usr/local/bin/python import sys, regex from string import strip pattDefine = regex.compile( '^#[\t ]*define[\t ]+\([a-zA-Z0-9_]+\)[\t ]*') pattInclude = regex.compile( '^#[\t ]*include[\t ]+[<"]\([a-zA-Z0-9_/\.]+\)') def scan(file): count = 0 while 1: # scan line-by-line line = file.readline() if not line: break count = count + 1 n = pattDefine.match(line) # save match length if n >= 0: name = pattDefine.group(1) # matched substring body = line[n:] print count, name, '=', strip(body) elif pattInclude.match(line) >= 0: regs = pattInclude.regs # start,stop a, b = regs[1] # of group 1 filename = line[a:b] # slice out print count, 'include', filename if len(sys.argv) == 1: scan(sys.stdin) # no args: read stdin else: scan(open(sys.argv[1], 'r')) # arg: input file name % cheader1.py test.h 1 include stdio.h 2 include usr/local/include/Py/Python.h 4 SPAM = 5 SHOE_SIZE = 7.5 7 include local_constants.h 8 PARROT = dead + bird
file: summer.py import string, sys def summer(numCols, fileName): sums = [0] * numCols for line in open(fileName, 'r').readlines(): cols = string.split(line) for i in range(numCols): sums[i] = sums[i] + eval(cols[i]) return sums if __name__ == '__main__': print summer(eval(sys.argv[1]), sys.argv[2]) % summer.py cols file
#!/usr/local/bin/python import os, sys # get unix, python services from stat import ST_SIZE # file stat record from glob import glob # file-name expansion from posixpath import exists # file exists test from time import time, ctime # time functions print 'RegTest start.' print 'user:', os.environ['USER'] # environment variables print 'path:', os.getcwd() # current directory print 'time:', ctime(time()), '\n' program = sys.argv[1] # two command-line args testdir = sys.argv[2] for test in glob(testdir + '/*.in'): # for all *.in files if not exists(test + '.out'): # no prior results command = '%s < %s > %s.out 2>&1' os.system(command % (program, test, test)) print 'GENERATED:', test else: # backup, run, compare os.rename(test + '.out', test + '.out.bkp') command = '%s < %s > %s.out 2>&1' os.system(command % (program, test, test)) command = 'diff %s.out %s.out.bkp > %s.diffs' os.system(command % ((test,)*3) ) if os.stat(test + '.diffs')[ST_SIZE] == 0: print 'PASSED:', test os.unlink(test + '.diffs') else: print 'FAILED:', test, '(see %s.diffs)' % test print 'RegTest done:', ctime(time()) % regtest.py shrubbery test1 RegTest start. user: mark path: /home/mark/stuff/python/testing time: Mon Feb 26 21:13:20 1996 FAILED: test1/t1.in (see test1/t1.in.diffs) PASSED: test1/t2.in RegTest done: Mon Feb 26 21:13:27 1996
And finally...
"Nobody expects the Spanish Inquisition..." Questions?
Copyright 1997, Mark Lutz