Why Python? =========== How do you evaluate a programming language? ------------------------------------------- Simplistic: CPU time, Memory usage, Lines of Code CPU is reasonably cheap, and memory is next, and developer time is the most expensive. At a higher level, the developer time issue comes down to ease of use, low overhead, solid standard and third party libraries, and similar issues. Python offers some advantages in these areas. What's so great about Python? ----------------------------- Python Language: - - - - - - - - - Simple,Elegant,Reliable,Powerful Simple: - Easy to read and understand - Easy to use - Easy to achieve most things - Fits in your brain - No unintended side-effects Elegant: - Compact, readable code - Low syntax overhead - Expressive - No visual/semantic conflicts Reliable: - Robust - Tested - Obvious - Less places for errors to hide - Open Source - Errors per KLOC ratio reasonably constant between programming langauges Powerful: - Able to achieve almost anything - Little code goes a long way - Can harness existing code in other languages or platforms - Extensibility, Jython, IronPython - Flexible - Portable, cross-platform Standard Library: - - - - - - - - - - Batteries included! - Protocols: HTTP, FTP, SMTP, POP3, IMAP, NNTP, ... - Markup support: HTML, SGML, XML - File formats: Mailbox, CSV, ZIP, TAR - Servers: HTTP, XMLRPC - Debugging, logging, URL manipulation, profiling, regular expressions, ... Third Party: - - - - - - - - - Twisted - Protocols: DNS, FTP, IRC, Jabber, MSN, AOL/Oscar, Shoutcast, SIP, ... Cheetah - Powerful template language (like Mason, Velocity, Smarty) Webware - Servlet-based application server Zope - Python Application Server, used for CMS, Plone, &c. Quotes ------ Bruce Eckel: Designed to maximise productivity, doesn't treat me like I'm stupid, my first guess is usually right, focus on concepts Who Uses Python --------------- Industrial Light & Magic relies on Python in their production pipeline, every computer-generated image from ILM has had Python involved in its creation somehow. Google! Various computer games, from the massively-multiplayer EVE mostly developed in Python to games such as Temple of Elemental Evil and Ages of Myst which embeds it as their game scripting language. Mark Shuttleworth's Thawte Consulting used Python as a productive way to manage large codebases in a rapidly evolving way. In the open source world: RedHat's install system (anaconda) is written in Python, as is Gentoo's package management system, portage. NASA's Integrated Planning System uses Python as the standard agile language, and NASA's Mission Control Centre uses Python. Data Types ========== Strings ------- "asdf" 'asdf' """John said "Foo is a bad dog", and walked away.""" '''Foo is Peter's dog''' print ----- print "Hello" print "Hello", print "There" variables and assignment ------------------------ a = 1 b = a + 5 c = (b * 3) + 2 a, b = 6 + 4, 1 + 3 a, b = b, a raw_input (using a function) --------- name = raw_input("Give me your name") Lists/sequences --------------- l = [] l2 = ["a", 2, b * 3] print l2[0] l.append(3) l2.remove(2) Dictionaries ("Associative arrays") ------------ d = {} d['hello'] = "there" d['Peter'] = "Pan" del d['hello'] d.get('foo', None) d.has_key('Peter') d.setdefault('Mozilla', 0) d.keys() d.values() d.items() Formatting strings ------------------ "I have %d apples in my %s" % (1, "bag") Sequence operations ------------------- Strings are also sequences "Slices" are parts of sequences "Harry Potter"[1:4] is "arr" "Harry Potter"[7:-2] is "ott" Blocks ====== indentation ----------- Indentation is used as the only means to determine which block a piece of code belongs to: C: if (a) if (b) a = 0 if (c) b = 1 if (d) e = 1 But that maps to, in reality: if (a) { if (b) { a = 0 } if (c) { b = 1 } } if (d) { e = 1 } This is a visual/semantic conflict. Programmers should be indenting anyway. It's even less work to just not type the braces. Also forces code to look somewhat uniform, and easy to read. pass ---- "Do nothing, but fill a line." Necessary for an empty block. for --- for fruit in ["apple", "banana"]: print "%s is a fruit, I like them." % (fruit) for line in file("/etc/fstab"): print line for letter in "Hello there": print letter while ----- x = 1 while x < 10: print x x += 1 if -- x = 1 y = 5 if x > y: print "%s is greater than %s" % (x, y) else x < y: print "%s is smaller than %s" % (x, y) else: print "%s has the same value as %s" % (x, y) functions --------- def twice(a): b = a * 2 return b Classes ======= class classname (parentclass1, ...): classvar = 1 def method1(self, arg1, ...): return "stuff" Classes are ways to create new types of objects. Everything in Python is an object. Classes explain how to interact with the object, and should contain data about the specific instance of an object. Objects are data and behaviour. Classes also explain to the rest of the language how the objects of their type interact with other objects. This allows you to add an integer to a time object, for example. It also allows you to change how the object displays itself as a string. Or how sequence operators work on the object. Explaining Object Orientation is beyond the scope of this talk. List comprehensions ------------------- Powerful and elegant way of creating one list from another, based on the values of the first list. Say you want to double everything in a list: l2 = [x * 2 for x in l1] Which means, for every item in list l1, put double that item in list l2. Let's say you want to remove certain items in a list to create another list, based on some comparison or function: l2 = [x for x in l1 if x > 5] Which means, for every item in list l1, put that item in list l2, but only if it is greater than 5. You can combine this easily enough: l2 = [3 * x for x in l1 if x < 27] You don't have to provide only one return value: l2 = [(x, x ** 2) for x in [0, 1, 2, 3, 4, 5, 6, 7, 8] if x % 2 == 0] This will create a list, each item is the original number and that number squared, starting from 0 and ending at 8, but only the even numbers. This isn't just useful for showing off. Let's say you have a map of people you know and their phone numbers. p = { 'John': '021 797 5432', 'Peter': '011 872 7652', 'Joan': '031 381 8127', 'Mary': '083 143 1823', 'Barry': '021 432 1943', } Now you want to know who you know in Cape Town: l2 = ["%s lives in Cape Town, and the number is %s" % (person, number) for person, number in p.items() if number.startswith('021')] for a in l2: print a Barry lives in Cape Town, and the number is 021 432 1943 John lives in Cape Town, and the number is 021 797 5432 Batteries Included! =================== email ----- import smtplib from email.MIMEText import MIMEText fp = open('/tmp/message') # Create a text/plain message msg = MIMEText(fp.read()) me = 'me@my.domain' you = 'you@your.domain' msg['Subject'] = 'That stuff you wanted' msg['From'] = me msg['To'] = you s = smtplib.SMTP() s.connect() s.sendmail(me, [you], msg.as_string()) s.close() mailbox ------- import email import mailbox maildir = mailbox.Maildir('Maildir', email.message_from_file) for mail in maildir: print mail["Date"] Making a mailing list program from just these few modules would be simple and functional. The email module provides the ability to manipulate the message, the mailbox module provides the ability to receive the message, and the smtplib module provides the ability to send the message. simple mailing list program --------------------------- import smtplib import email import mailbox maildir = mailbox.Maildir('Maildir', email.message_from_file) to = ['first1@company1', 'first2@company2', ... ] listprefix = '[ListName] ' s = smtplib.SMTP() s.connect() for mail in maildir: mail['List-Id'] = foo if listprefix not in mail['Subject']: mail['Subject'] = listprefix + mail['Subject'] mail['From'] = 'Original sender hidden ' s.sendmail(me, [you], mail.as_string()) s.close() SQLObject --------- from SQLObject import * __connection__ = MySQLConnection(db='foo', user='root') class Subscriber(SQLObject): address = StringCol(alternateID=True) name = StringCol() added = DateTimeCol() admin = BoolCol(default=False) bounces = IntCol(default=0) Subscriber.createTable()