Fifty awesome things
in the standard library

Andy McKay
@andymckay
github.com/andymckay/presentations

Why?

Some languages don't even have a standard library.

It's got some great stuff.

It's got some not so great stuff.

Rules

Must in 2.x or 3.x standard library.

Python version added will be noted if recent.

Fun or just jolly useful counts.

argparse

1
>>> import argparse
>>> parser = argparse.ArgumentParser()
...[snip]
>>> parser.parse_args(['--sum', '7', '-1', '42'])
Namespace(accumulate=, integers=[7, -1, 42])
2.6

atexit

2
>>> import atexit, os
>>> os.path.exists('confoo.txt')
True
>>> def cleanup(): os.system('rm confoo.txt')
...
>>> atexit.register(cleanup)

>>> ^D
$ ls confoo.txt
ls: confoo.txt: No such file or directory

codecs

3
>>> import codecs
>>> codecs.open('example.txt', 'r',
...             'utf-8', 'strict').read()
u'\u0540\u0561\u0575\u0561\u057d\u057f\u0561\u0576\n'

contextlib.contextmanager

4
>>> from contextlib import contextmanager
>>> @contextmanager
... def tag(name):
...     print "<%s>" % name,
...     yield
...     print "</%s>" % name
...
>>> with tag('h1'): print 'hello',
...
'<h1> hello </h1>'
2.5

collections.defaultdict

5
>>> from collections import defaultdict
>>> beer = defaultdict(lambda: defaultdict(dict))
>>> beer['guinness']['colour'] = 'black'
>>> beer['guinness']['colour']
'black'
2.5

collections.Counter

6
>>> from collections import Counter
>>> food = Counter(['eggs', 'bacon'])
>>> food['eggs']
1
>>> food['ham']
0
>>> food += Counter(['eggs', 'ham'])
>>> food['eggs']
2
>>> food['ham']
1
2.4

collections.OrderedDict

7
>>> from collections import OrderedDict
>>> o = OrderedDict()
>>> o['x'] = 'X'
>>> o['y'] = 'Y'
>>> o.keys()
['x', 'y']
2.7

collections.namedtuple

8
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(3, 4)
>>> p.x
3
2.6

ctypes

9
>>> from ctypes import *
>>> print windll.kernel32
<WinDLL 'kernel32', handle ... at ...>
2.5
complicated.

decimal.Decimal

10
>>> from decimal import Decimal
>>> Decimal('3.14214').quantize(Decimal('.01'))
Decimal('3.14')
2.4

dis

11
>>> from urllib import urlopen
>>> import dis
>>> dis.dis(urlopen)
 73           0 LOAD_CONST               1 (-1)
              3 LOAD_CONST               2 (('warnpy3k',))
              6 IMPORT_NAME              0 (warnings)

functools.partial

12
>>> import functools, os
>>> os.path.join('/some/root', 'bar')
'/some/root/bar'
>>> join = functools.partial(
...   os.path.join, '/some/root')
>>> join('bar')
'/some/root/bar'
2.5

functools.total_ordering

13
>>> from functools import total_ordering
>>> @total_ordering
... class Person:
...     def __init__(self, age):
...         self.age = age
...     def __lt__(self, other):
...         return self.age < other.age
...
>>> print Person(45) >= Person(5)
True
2.7

functools.wraps

14
>>> from functools import wraps
>>> def my_decorator(f):
...     @wraps(f)
...     def wrapper(*args, **kwds):
...         return f(*args, **kwds)
...     return wrapper
2.5

glob.glob

15
>>> from glob import glob
>>> glob('apps/*/*.py')
['apps/abuse/__init__.py',
 'apps/access/__init__.py', ...]

imaplib

16
>>> import imaplib
>>> imap = imaplib.IMAP4('mail.mozilla.com', 993)
>>> imap.login('user', 'pass')
>>> imap.select()
>>> typ, data = imap.search(None, 'ALL')
>>> for num in data[0].split():
...    typ, data = imap.fetch(num, '(RFC822)')
...    print 'Message %s\n%s\n' % (num, data[0][1])
>>> imap.close()
>>> imap.logout()

importlib.import_module

17
>>> from importlib import import_module
>>> import_module('urllib')
<module 'urllib' from ...>
2.7

inspect.getmoduleinfo

18
>>> import inspect
>>> inspect.getmoduleinfo('../settings_local.pyc')
ModuleInfo(name='settings_local', suffix='.pyc',
           mode='rb', module_type=2)
2.1

inspect.getsource

19
>>> import inspect, urllib
>>> inspect.getsource(urllib.urlopen)
'def urlopen(url, data=None, proxies=None):\n...'
2.1

inspect.stack

20
>>> import inspect
>>> inspect.stack()
[(<frame object at 0x7fdd21cbf490>, '<stdin>', 1,
 '<module>', None, None)]

itertools.groupby

21
>>> from itertools import groupby
>>> x = [1,1,3,3,3,3,3,4,5,6]
>>> for x, g in groupby(x):
...     print x; print [y for y in g]
...
1
[1, 1]
3
[3, 3, 3, 3, 3]
2.4

itertools.chain

22
>>> from itertools import chain
>>> for x in chain('a', 'bc'):
...     print x
...
a
b
c
2.4

itertools.imap

23
>>> from itertools import imap
>>> for x in itertools.imap(str.upper, ['a','b']):
...     print x
...
A
B
2.4

json

24
$ echo '{"foo": "lorem", "bar": "ipsum"}'\
  | python -m json.tool
{
    "bar": "ipsum",
    "foo": "lorem"
}
2.6

locale

25
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'fr_FR')
'fr_FR'
>>> locale.currency(10)
'10,00 Eu'

operator

26
>>> import operator
>>> map(operator.mul, [1,2,3], [4,5,6])
[4, 10, 18]

pdb

27
$ python -m pdb foo.py
> foo.py(1)()
-> import smtplib
(Pdb)

pdb.set_trace

28
>>> import pdb; pdb.set_trace()
--Return--
> (1)()->None
(Pdb)

pdb.pm

29
>>> import pdb
>>> import mymodule
>>> mymodule.test()
Traceback (most recent call last):
  File "./mymodule.py", line 3, in test2
    print spam
NameError: spam
>>> pdb.pm()
> ./mymodule.py(3)test2()
-> print spam
(Pdb)

profile

30
$ python -m profile foo.py -s ncalls
5961 function calls (5896 primitive calls) in 0.076...

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    13    0.000    0.000    0.000    0.000 :0(__contains__)
     2    0.000    0.000    0.000    0.000 :0(_getframe)
    11    0.000    0.000    0.000    0.000 :0(add)
    13    0.000    0.000    0.001    0.000 :0(all)
   327    0.001    0.000    0.001    0.000 :0(append)

re » expand

31
>>> import re
>>> match = re.match('(?P<first>\w+) (?P<last>\w+)',
                     'Isaac Newton')
>>> match.expand('\g<last> \g<first>')
'Newton Isaac'

sets (and set)

32
>>> set([1,2,3]).intersection(set([3,4,5]))
set([3])
2.3 » 2.6 (now a built-in)

SimpleHTTPServer

33
$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

smtpd

34
$ python -m smtpd -n -c DebuggingServer localhost:2000
---------- MESSAGE FOLLOWS ----------
From: bob@site.com
To: jane@site.com
X-Peer: 127.0.0.1

ConFoo
------------ END MESSAGE ------------

subprocess.check_output

35
>>> res = subprocess.check_output(["ls", "-l"])
>>> res
'total 296\n-rw-r--r--  1 andy  staff...'

tempfile

36
>>> import os
>>> from tempfile import NamedTemporaryFile
>>> tmp = NamedTemporaryFile()
>>> tmp.name
'/var/folders/g_/d41tpd...'
>>> os.path.exists(tmp.name)
True
>>> tmp.close()
>>> os.path.exists(tmp.name)
False
2.3

timeit.timeit

37
>>> import timeit
>>> timeit.timeit(
...     '",".join(str(n) for n in range(100))',
...     number=10000)
0.41231489181518555
2.3

trace

38
$ python -m trace --trace foo.py
 --- modulename: threading, funcname: settrace
threading.py(90):     _trace_hook = func
 --- modulename: foo, funcname: 
foo.py(1): import smtplib
 --- modulename: smtplib, funcname: 
smtplib.py(33): '''
smtplib.py(44): import socket
 --- modulename: socket, funcname: 
socket.py(44): """
socket.py(46): import _socket

unicodedata.lookup

39
$ python -c "import unicodedata;\
  print unicodedata.lookup('SNOWMAN')"

unittest.mock » Mock

40
>>> from unittest.mock import Mock
>>> thing = Mock()
>>> thing.method()
<Mock name='mock.method()' id='4467254992'>
>>> thing.method.return_value = 3
>>> thing.method()
3
3.3

unittest.mock » patch

41
@patch('requests.post')
def test_auth_fails(self, post):
    post.side_effect = AuthError
    with self.assertRaises(AuthError):
         self.paypal.call('get-pay-key', {})
3.3

urllib.parse.urlparse

42
>>> from urllib.parse import urlparse, urlunparse
>>> urlparse('http://mozilla.org')
ParseResult(scheme='http', netloc='mozilla.org',
            path='', params='', query='',
            fragment='')
>>> urlunparse(urlparse('http://mozilla.org'))
'http://mozilla.org'
called urlparse in Python 2.

uuid.uuid1

43
>>> import uuid
>>> uuid.getnode()
123516846201053
>>> str(uuid.uuid1())
'd4547447-8047-11e2-be45-705681bdd8dd'
2.5

venv.create

44
>>> import venv
>>> venv.create('/tmp/venv')
3.3
virtualenv is awesome

wsgiref

45
>>> from wsgiref.simple_server import make_server
>>> def hello_world_app(environ, start_response):
...     start_response(
          '200 OK',
          [('Content-type', 'text/plain')])
...     return ['Hello world']
...
>>> httpd = make_server('', 8000, hello_world_app)
>>> httpd.serve_forever()
2.5

wsgiref » error_status

bonus
>>> from wsgiref import handlers
>>> handlers.BaseHandler.error_status
'500 Dude, this is whack!'
2.5

xml.etree.ElementTree

46
>>> import xml.etree.ElementTree
>>> tree = ElementTree.parse('country_data.xml')
>>> tree.getroot().findall('country')
[<Element country at 1084a6248>, ...]
2.5

"Easter Eggs"

this

47
>>> import this
The Zen of Python, by Tim Peters

Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
... [snip]

__future__.braces

48
>>> from __future__ import braces
  File "", line 1
SyntaxError: not a chance

Friendly Language
Uncle For Life

49
>>> from __future__ import barry_as_FLUFL
>>> print(3!=4)
  File "", line 1
    print(3!=4)
            ^
SyntaxError: invalid syntax
>>> print(3<>4)
True

antigravity

50
>>> import antigravity
3

Notable exceptions

httplib, urllib, urllib2 etc. Use requests.

xml etc (mostly). Use lxml.

threading, asyncore etc. Relevant?
Use gevent, tornadio, twisted (maybe).

Fin

@andymckay
github.com/andymckay/presentations