Version: | 0.2 of 03.06.2010 |
---|
Contents
I am:
This tutorial is mostly borrowing from:
Also useful:
Type python at the command line. You should get:
Python 2.6 (#1, Feb 28 2007, 00:02:06) Type "help", "copyright", "credits" or "license" for more information. >>>
Our first program:
>>> world_is_flat = 1 >>> if world_is_flat: ... print "Don't fall off!" ... Don't fall off!
Use Python as a calculator:
>>> 2+2 4 >>> 2+2 # a comment on the same line as code 4
The operators +, -, *, /, ( and ) work just like in most other languages:
>>> 50-5*6 20 >>> (50-5)*6 270
Integer division returns the floor (before Python 3.x):
>>> 7/3 2 >>> 7/-3 -3
The equal sign (=) is used to assign a value to a variable:
>>> width = 20 >>> height = 5*9 >>> width * height 900
Floating point operations:
>>> 3 * 3.75 / 1.5 7.5 >>> 7.0 / 2 3.5
The last printed expression is assigned to the variable _:
>>> tax = 12.5 / 100 >>> price = 100.50 >>> price * tax 12.5625
>>> _ 12.5625 >>> price + _ 113.0625 >>> round(_, 2) 113.06
>>> 'spam eggs' 'spam eggs' >>> 'doesn\'t' "doesn't" >>> '"Yes," he said.' '"Yes," he said.'
>>> print """ ... Usage: thingy [OPTIONS] ... -h Display this usage message ... -H hostname Hostname to connect to ... """ Usage: thingy [OPTIONS] -h Display this usage message -H hostname Hostname to connect to
+ and * operator:
>>> word = 'Help' + 'A' >>> word 'HelpA' >>> '<' + word*5 + '>' '<HelpAHelpAHelpAHelpAHelpA>'
Indexing works like in C. There's no separate character type:
>>> word 'HelpA' >>> word[4] 'A'
Substrings using the slice notation:
>>> word[0:2] 'He' >>> word[2:4] 'lp'
Slice indexes have useful defaults:
>>> word[:2] # The first two characters 'He' >>> word[2:] # Everything except \ ... # the first two characters 'lpA'
Python strings are immutable. Assigning to an indexed position results in an error:
>>> word[0] = 'x' Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: 'str' object does not support item assignment
However, creating a new string is easy and efficient:
>>> 'x' + word[1:] 'xelpA' >>> 'Splat' + word[4] 'SplatA'
Out-of-range slice indices are handled gracefully:
>>> word[1:100] 'elpA' >>> word[10:] '' >>> word[2:1] ''
Indices may be negative numbers, to start counting from the right:
>>> word[-1] # The last character 'A' >>> word[-2] # The last-but-one character 'p'
>>> word[-2:] # The last two characters 'pA' >>> word[:-2] # Everything except the last two characters 'Hel' >>> word[-100:] # Out-of-range index is truncated 'HelpA'
The built-in function len returns the length of a string:
>>> s = 'supercalifragilisticexpialidocious' >>> len(s) 34
>>> a = ['spam', 'eggs', 100, 1234] >>> a ['spam', 'eggs', 100, 1234]
Like strings, lists support index operations:
>>> a[0] 'spam' >>> a[3] 1234 >>> a[-2] 100
Lists can be sliced and concatenated:
>>> a[1:-1] ['eggs', 100] >>> a[1:-1] ['eggs', 100] >>> a[:2] + ['bacon', 2*2] ['spam', 'eggs', 'bacon', 4] >>> 2*a[:2] + ['Boo!'] ['spam', 'eggs', 'spam', 'eggs', 'Boo!']
Unlike with strings, it's possible to change individual elements of a list:
>>> a ['spam', 'eggs', 100, 1234] >>> a[2] = a[2] + 23 >>> a ['spam', 'eggs', 123, 1234]
Assignments to slices is also possible:
>>> # Replace some items: ... a[0:2] = [1, 12] >>> a [1, 12, 123, 1234] >>> # Remove some: ... a[0:2] = [] >>> a [123, 1234]
>>> # Insert some: ... a[1:1] = ['bletch', 'xyzzy'] >>> a [123, 'bletch', 'xyzzy', 1234] >>> # Insert (a copy of) itself: ... a[:0] = a >>> a [123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234]
The built-in function len also works with lists:
>>> a = ['a', 'b', 'c', 'd'] >>> len(a) 4
It's possible to nest lists:
>>> q = [2, 3] >>> p = [1, q, 4] >>> len(p) 3 >>> p[1] [2, 3]
>>> p[1].append('xtra') >>> p [1, [2, 3, 'xtra'], 4] >>> q [2, 3, 'xtra']
Note that p[1] and q refer to the same object!
Fibonacci series; the sum of two elements defines the next:
>>> a, b = 0, 1 >>> while b < 1000: ... print b, ... a, b = b, a+b ... 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> s = [1, 2] >>> len(s) >= 3 False >>> if s: ... print "Non-empty" ... print "Length:", len(s) Non-empty Length: 2
>>> x = 42 >>> if x < 0: ... x = 0 ... print 'Negative changed to zero' ... elif x == 0: ... print 'Zero' ... elif x == 1: ... print 'Single' ... else: ... print 'More' ... More
>>> # Measure some strings: ... a = ['cat', 'window', 'defenestrate'] >>> for x in a: ... print x, len(x) ... cat 3 window 6 defenestrate 12
It is not safe to modify the sequence being iterated over. Make a copy if you need to:
>>> for x in a[:]: # make a slice copy ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrate', 'cat', 'window', 'defenestrate']
The range function generates lists containing arithmetic progressions:
>>> range(10) # end point is never part of the list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> range(5, 10) # range starts at 5 [5, 6, 7, 8, 9] >>> range(0, 10, 3) # increment is 3 [0, 3, 6, 9]
<<< a ['defenestrate', 'cat', 'window', 'defenestrate'] <<< f = raw_input("Find: ") Find: window <<< for x in a: ... if f == x: ... print "Found", f ... break ... Found window
Loop statements may have an else clause that's executed when the loop was not terminated by a break.
>>> f = 'dog' >>> for x in a: ... if f == x: ... print "Found", f ... break ... else: ... print f, "not found" dog not found
Write a program that for each number between 2 and 9:
You'll use for, range, break, and else.
You'll need the modulo operator %:
>>> 9 / 4 2 >>> 9 % 4 1
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, 'equals', ... print x, '*', n/x ... break ... else: # inner loop fell through ... print n, 'is a prime number' ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3
>>> def replace(s, fro, to): ... for i in range(len(s)): ... if s[i] == fro: ... s[i] = to >>> k = ['one', 'two'] >>> replace(k, 'one', 'three') >>> k ['three', 'two']
Defining a function introduces the name in the current symbol table.
The function can be assigned to another name:
>>> r = replace >>> r(k, 'three', 1) >>> k [1, 'two']
Write a function that writes the Fibonacci series to an arbitrary boundary.
>>> def fib(n): ... """Print Fibonacci series up to n.""" ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # Now call the function we just defined: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Isn't fib really a procedure since it returns no value? Python functions always have a default return value, which is None. It's not printed by the interactive mode:
>>> fib(0) >>> print fib(0) None
Use the return keyword to return a value from a function:
>>> def absadd(a, b): ... return abs(a + b) >>> absadd(-5, -10) 15 >>> a = absadd(absadd(-5, -10), -100) >>> a 85
Modify your Fibonacci function to return a list instead of printing numbers.
You'll use the append method of lists:
>>> l = [1, 5] >>> l.append('Nine') >>> l [1, 5, 'Nine']
>>> def fib2(n): ... """Fibonacci series up to n.""" ... result = [] ... a, b = 0, 1 ... while b < n: ... result.append(b) ... a, b = b, a+b ... return result
Write a function replace2 that works like the replace we defined earlier with the exception that it doesn't modify the list that we pass to it, but returns a new list.
>>> def replace2(s, fro, to): ... s = s[:] # copy ... for i in range(len(s)): ... if s[i] == fro: ... s[i] = to ... return s >>> s = ['spam', 'eggs'] >>> replace2(s, 'eggs', 'butter') ['spam', 'butter'] >>> s ['spam', 'eggs']
>>> f100 = fib2(100) >>> f100 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
It's possible to define functions with a variable number of arguments, like range:
>>> range(5) [0, 1, 2, 3, 4] >>> range(1, 5) [1, 2, 3, 4] >>> range(1, 6, 2) [1, 3, 5]
Default argument values are very useful:
>>> def replace3(s, fro, to, count=0): ... s = s[:] ... for i in range(len(s)): ... if s[i] == fro: ... s[i] = to ... count = count - 1 ... if count == 0: break ... return s
>>> replace3(['one', 'two', 'one', 'two'], ... 'one', 'three') ['three', 'two', 'three', 'two'] >>> replace3(['one', 'two', 'one', 'two'], ... 'one', 'three', 1) ['three', 'two', 'one', 'two']
>>> def ask_ok(prompt, retries=4, ... complaint='Yes or no, plz!'): ... """Prompt the user for yes or no. ... Return True for positive answer or ... False for negative answer. User will ... be prompted a maximum of ``retries`` ... times before ``IOException`` is ... raised. ... """
Your program should:
How to raise an exception?
>>> input = 'N' >>> if input == 'yes': ... value = True ... elif input == 'no': ... value = False ... else: ... raise ValueError("Invalid input!") Traceback (most recent call last): ValueError: Invalid input!
Extra: Add tolerance so that the user can enter any of y, ye, and yes to answer positively, and any of n, no, nope to answer negatively. For this, you may want to try the in operator:
>>> 'one' in ['two', 'three'] False
>>> def ask_ok(prompt, retries=4, ... complaint='Yes or no, please!'): ... while True: ... ok = raw_input(prompt) ... if ok in ('y', 'ye', 'yes'): ... return True ... if ok in ('n', 'no', 'nope'): ... return False ... retries = retries - 1 ... if retries < 0: ... raise IOError('refusenik user') ... print complaint
The function can be called like this:
Arbitrary argument lists are less frequent:
>>> def cheeseshop(kind, *arguments, **keywords): ... print "-- Do you have any", kind, "?" ... print "-- I'm sorry, we're all out of", kind ... for arg in arguments: ... print arg ... print "-" * 40 ... keys = keywords.keys() ... keys.sort() ... for kw in keys: print kw, ":", keywords[kw]
>>> cheeseshop("Limburger", "It's very runny, sir.", ... "It's really very, VERY runny, sir.", ... shopkeeper='Michael Palin', ... client="John Cleese", ... sketch="Cheese Shop Sketch") -- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch
If your arguments are already in a list (or tuple), you can use the * operator to unpack the arguments:
>>> range(3, 6) # normal call [3, 4, 5] >>> args = [3, 6] >>> range(*args) # arguments unpacked [3, 4, 5]
The same works with keyword arguments and dictionaries:
>>> def parrot(voltage, state='a stiff', action='voom'): ... print "-- This parrot wouldn't", action, ... print "if you put", voltage, "volts through it.", ... print "E's", state, "!" >>> d = {"voltage": "four million", ... "state": "bleedin' demised", ... "action": "VOOM"} >>> parrot(**d) -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
Write a function range2 that acts just like the Python built-in.
You'll probably use a variable number of positional, non-keyword arguments.
To remind yourself how range works, see help(range).
>>> def range2(*args): ... start, step = 0, 1 ... if len(args) > 1: ... start, stop = args[:2] ... else: ... stop = args[0] ... if len(args) == 3: ... step = args[2] ... return range(start, stop, step)
>>> range2(5) [0, 1, 2, 3, 4] >>> range2(1, 5) [1, 2, 3, 4] >>> range2(1, 6, 2) [1, 3, 5]
Python has great built-in documentation facilities. Try help(max) or help(filter).
Use max to find the largest element of the list l.
Use filter to remove all zeros from a list of numbers like this one:
>>> l = [5, 4, 3, 0, 2, 1, 0]
How to know what methods a list has? Remember there was l.append.
What other methods exist? Try dir(l). For each method, you can do help(method), like help(l.insert). You can also do help(l).
Write a function sort_in that takes a list and an element to sort into the list. The function should modify the list in place and expect the list to be sorted already.
You'll probably use range. Try out l.insert.
Let's also look at how enumerate works:
>>> for index, value in enumerate( ... ['un', 'deux', 'trois']): ... print index, value ... 0 un 1 deux 2 trois
>>> def sort_in(s, el): ... for index, item in enumerate(s): ... if el < item: ... break ... else: ... index = len(s) ... s.insert(index, el) ... return s
Let's try it out:
>>> sort_in([3, 5], 4) [3, 4, 5] >>> sort_in([], 3) [3] >>> sort_in([5], 3) [3, 5] >>> sort_in([5], 6) [5, 6]
For more sorting, check out the sorted built-in.
Try sorted to reverse sort the items in a list.
>>> s = ['a', 'z', 'b', 'f'] >>> sorted(s, reverse=True) ['z', 'f', 'b', 'a'] >>> s # s is still the old list ['a', 'z', 'b', 'f'] >>> s.sort(reverse=True) # in-place >>> s ['z', 'f', 'b', 'a']
Functions in Python are first class objects:
>>> def divide_by_2(x): ... return x / 2 ... >>> divide_by_2 <function divide_by_2 at ...> >>> divide_by_2(10) 5
We can pass one function as an argument to another:
>>> def is_lower(s): ... return s.islower() >>> filter(is_lower, ... ['Spam', 'eggs', 'limBurger']) ['eggs']
Create functions on the fly:
>>> def divide_by_factory(n): ... def divide_by_n(x): ... return x / n ... return divide_by_n >>> divide_by_2 = divide_by_factory(2) >>> divide_by_5 = divide_by_factory(5) >>> divide_by_2(10) 5 >>> divide_by_5(50) 10
Easier to read than filter:
>>> l = ['Spam', 'eggs', 'limBurger'] >>> [w for w in l if w.islower()] ['eggs']
sorted takes an optional key argument. If provided, this must be a function that takes an element and returns a value suitable for sorting that element: a predicate.
Write a function even_sort that takes a list with numbers and returns a new list with even numbers before odd ones.
So [4, 5, 6, 7, 8] will result in [4, 6, 8, 5, 7].
>>> def modulo2(number): ... return number % 2 >>> def even_sort(s): ... return sorted(s, key=modulo2) >>> even_sort([4, 5, 6, 7, 8]) # stable [4, 6, 8, 5, 7]
With the keyword lambda, small anonymous functions can be created. This function:
>>> lambda a, b: a + b <function <lambda> at ...>
Is equivalent to this one:
>>> def add(a, b): ... return a + b
We can also assign the former a name:
>>> add = lambda a, b: a + b >>> add(5, -3) 2
Instead of defining a separate modulo2 function, we can use a lambda function with even_sort:
>>> def even_sort2(s): ... return sorted(s, key=lambda n: n%2) >>> even_sort2([4, 5, 6, 7, 8]) [4, 6, 8, 5, 7]
Use sorted to reverse the order of a list. But this time, don't use the reverse argument, but do it with a key parameter.
These two are thus equivalent:
>>> sorted([5, 9, 3, 5], key=lambda n:-n) [9, 5, 5, 3] >>> sorted([5, 9, 3, 5], reverse=True) [9, 5, 5, 3]
LIFO:
>>> stack = [3, 4, 5] >>> stack.append(6) >>> stack.append(7) >>> stack [3, 4, 5, 6, 7]
>>> stack [3, 4, 5, 6, 7] >>> stack.pop() 7 >>> stack [3, 4, 5, 6] >>> stack.pop() 6
FIFO:
>>> queue = ["Eric", "John", "Michael"] >>> queue.append("Terry") # Terry arrives >>> queue.append("Graham") # Graham arrives >>> queue.pop(0) 'Eric' >>> queue ['John', 'Michael', 'Terry', 'Graham']
open returns a file object, and is most commonly used with two arguments: open(filename, mode).
>>> f = open('/tmp/workfile', 'w') >>> print f <open file '/tmp/workfile', mode 'w' at ...>
The second argument is a string containing a few characters describing the way in which the file will be used:
On Windows, 'b' appended to the mode opens the file in binary mode, so there are also modes like 'rb', 'wb', and 'r+b'. Windows makes a distinction between text and binary files; the end-of-line characters in text files are automatically altered slightly when data is read or written.
Let's write to our previously opened file:
>>> f.write('This is the first.\n') >>> f.close() # flush
We can now read it:
>>> f = open('/tmp/workfile') # 'r' default >>> f.read() # read the entire file 'This is the first.\n' >>> f.close()
Let's write more to our file:
>>> f = open('/tmp/workfile', 'a') >>> f.write("""This is the second, ... and this is the third line. ... """) >>> f.close() # flush
We can read lines by looping over the file object:
>>> f = open('/tmp/workfile', 'r') >>> for line in f: ... print line, # includes \n This is the first. This is the second, and this is the third line. >>> f.close()
Write a function replacef that takes the name of a file, and two strings. The function should replace in the given file all occurrences of the first string by the second one.
>>> def replacef(fn, fro, to): ... f = open(fn) ... contents = f.read() ... f.close() ... f = open(fn, 'w') ... f.write(contents.replace(fro, to)) ... f.close()
Let's try it out:
>>> replacef('/tmp/workfile', ' is', ' be') >>> f = open('/tmp/workfile') >>> print f.read() This be the first. This be the second, and this be the third line. >>> f.close()
The encode and decode methods of strings are useful:
>>> s = 'Hello, Python African Tour!'.encode('base64') >>> s 'SGVsbG8sIFB5dGhvbiBBZnJpY2FuIFRvdXIh\n' >>> s.decode('base64') 'Hello, Python African Tour!'
Let's create our first script:
Write:
def encode_rot13(fn_in, fn_out): f = open(fn_in) contents = f.read() f.close() f = open(fn_out, 'w') f.write(contents.encode('rot13')) f.close()
At the end, write:
if __name__ == '__main__': import sys encode_rot13(sys.argv[1], sys.argv[2])
Call it:
python rot13.py myfile.txt myfile-encoded.txt
Write a script:
encode.py <encoding> <firstfile> <secondfile>
Encode the <firstfile> and write out to <secondfile>.
Extra: If <secondfile> is ommitted, then <firstfile> should be overwritten.
Look at sys.argv.
Extra:
encode <dec> <enc> <firstf> <secondf>
E.g.:
encode iso-8859-1 utf-8 orig.txt conv.txt
You'll need ''.encode and ''.decode methods!
Tuples are like lists, except that they're immutable, like strings:
>>> t = (12345, 54321, 'hello!') >>> t[0] 12345 >>> t[0] = 67890 Traceback (most recent call last): ... TypeError: 'tuple' object does not support item assignment
A nice feature of Python is sequence unpacking:
>>> x, y, z = t >>> x 12345 >>> y 54321 >>> z 'hello!'
We saw sequence unpacking before, with enumerate:
>>> for index, item in enumerate( ... ("Un", "Deux", "Trois")): ... print index, item 0 Un 1 Deux 2 Trois >>> tuple(enumerate(("Un", "Deux", "Trois"))) ((0, 'Un'), (1, 'Deux'), (2, 'Trois'))
A set is an unordered collection with no duplicate elements:
>>> basket = ['apple', 'orange', 'apple', ... 'pear', 'orange', 'banana'] >>> fruit = set(basket) # no duplicates >>> fruit set(['orange', 'pear', 'apple', 'banana'])
>>> 'orange' in fruit # fast test True >>> 'crabgrass' in fruit False >>> fruit.add('strawberry') >>> len(fruit) 5
Set operations on word letters:
>>> a = set('abracadabra') >>> b = set('alacazam') >>> a # unique letters in a set(['a', 'r', 'b', 'c', 'd']) >>> a - b # letters in a but not in b set(['r', 'b', 'd'])
Set operations on word letters contd.:
>>> union = a | b >>> intersection = a & b >>> xor = a ^ b
Write a script common.py:
python common.py <file1> [file2] [file3] [...]
This script should print out a sorted list of common words in all files.
Use the ''.split method to get a list of words in a file.
>>> def common(contents): ... words = set(contents[0].split()) ... for s in contents[1:]: ... words &= set(s.split()) ... return sorted(words)
>>> common(["This is the first line", ... "This is the second line", ... "This is the third line", ... "This line is funny"]) ['This', 'is', 'line']
if __name__ == '__main__': all_contents = [] for fn in sys.argv[1:]: f = open(fn) all_contents.append(f.read()) f.close() common(all_contents)
Make common.py case-insensitive. Look at helpful methods of a string. Try help(str).
A dictionary is an unordered set of key: value pairs, with the requirement that the keys are unique.
A pair of braces creates an empty dictionary: {}. Placing a comma-separated list of key:value pairs within the braces adds initial key:value pairs to the dictionary, like {1: 'un'}.
Any immutable type can be used as a key, like strings and tuples. Lists may not be used as keys, since they can be modified in place.
The main operations are:
>>> tel = {'jack': 4098, 'sape': 4139} >>> tel['guido'] = 4127 >>> tel['jack'] 4098
>>> tel {'sape': 4139, 'jack': 4098, 'guido': 4127} >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel {'jack': 4098, 'irv': 4127, 'guido': 4127} >>> tel.keys() ['jack', 'irv', 'guido'] >>> 'guido' in tel True
Looping over dictionaries:
>>> for key in tel: ... print key, jack irv guido >>> for key, value in tel.items(): ... print '%s: %s' % (key, value) jack: 4098 irv: 4127 guido: 4127
Make a script count.py that returns a list of words in a given file along with the number of their occurrences, like this:
33 is 25 there 21 are ...
>>> def count(text): ... table = {} ... for word in text.split(): ... table.setdefault(word, 0) ... table[word] += 1 ... return table
>>> def count_format(text): ... pairs = count(text).items() ... pairs.sort(key=lambda i:-i[1]) ... for word, occ in pairs: ... print occ, word
Let's try it out:
>>> f = open('/usr/share/doc/time/README') >>> count_format(f.read()) 5 and 5 the 2 program 2 GNU 2 as ... >>> f.close()
Our count program has a little problem: It'll interpret punctuation characters as part of a word, like with "there," or "file.".
Look at method ''.strip() to see how to fix this. Also look at the string module for useful constants. Use import string; help(string).
>>> import string >>> '-file;.'.strip(string.punctuation) 'file'
>>> import this The Zen of Python, by Tim Peters...
>>> yussuf = {'firstname': 'Yussuf', ... 'lastname': 'Islam'} >>> def fullname(record): ... value = record['firstname'] ... middlename = record.get('middlename') ... if middlename: ... value += ' ' + middlename ... value += ' ' + record['lastname'] ... return value
>>> fullname(yussuf) 'Yussuf Islam' >>> michael = {'firstname': 'Michael', ... 'lastname': 'Palin', ... 'middlename': 'Abraham'} >>> fullname(michael) 'Michael Abraham Palin'
>>> class Person: ... def __init__(self, firstname, lastname, ... middlename=''): ... self.firstname = firstname ... self.lastname = lastname ... self.middlename = middlename ... def fullname(self): ... value = self.firstname ... if self.middlename: ... value += ' ' + self.middlename ... value += ' ' + self.lastname ... return value
>>> me = Person('Daniel', 'Nouri') >>> john = Person('John', 'Cleese') >>> michael = Person( ... 'Michael', 'Palin', 'Abraham')
>>> me.firstname 'Daniel' >>> me.middlename '' >>> me.fullname() 'Daniel Nouri' >>> michael.fullname() 'Michael Abraham Palin'
>>> persons = [john, me, michael] >>> persons.sort() <<< persons[0].lastname 'Nouri' <<< persons[1].lastname 'Cleese' <<< persons[2].lastname 'Palin'
>>> class SortablePerson(Person): ... def __lt__(self, other): ... return self.lastname < other.lastname
>>> SP = SortablePerson >>> persons = [ ... SP('John', 'Cleese'), ... SP('Daniel', 'Nouri'), ... SP('Michael', 'Palin', 'Abraham'), ... ]
>>> persons.sort() >>> persons[0].fullname() 'John Cleese' >>> persons[1].fullname() 'Daniel Nouri' >>> persons[2].fullname() 'Michael Abraham Palin'