Learning Python: Unit 9, Built-ins (original) (raw)

���9. Built-in To���ols Overview

♦ Python's tool box

● Types and operations:�� lists, dictionaries, files, slices,�

● Functions:�� len, range, zip, getattr�

● Modules (Python and C):�� string, os, Tkinter, pickle,�

● Exceptions:�� IndexError, KeyError,�

● Attributes:�� __dict__, __name__,�

● Peripheral tools:�� NumPy, SWIG, Jython, PythonWin,�

Topics

♦ Debugging options

♦ Testing frameworks

♦ Timing and profiling Python programs

♦ Packaging Python programs

♦ Installation tools

♦ Development tools for larger projects

♦ Summary: Python tool set layers

But first, the secret handshake�

Debugging options

♦ �pdb� debugger: dbx-like command line interface

♦ Imported module, written in Python

♦ May also be run as script →� python -m pdb script.py

♦ Also see: �IDLE� Tkinter-based debugger GUI�

♦ See library manuals for pdbcommands and usage

Other error-handling tricks

● Error messages

● Top-level stack tracebacks

● Inserting print statements

● Outer exception handlers

defsafe(entry, *args):

��� try:

������� entry(*args)�������� # catch everything else (apply)

��� except:

������� import sys

������� print sys.exc_info()[0],sys.exc_info()[1]���# type, value

��

Debugging example

file: boom.py

def func(x, y):

��� return x / y

Session

>>> import boom

>>>boom.func(1, 0)

Traceback (innermost last):

� File "<stdin>", line 1, in ?

� File "boom.py", line 3, in func

��� return x / y

ZeroDivisionError: integer division or modulo

>>>

>>> import pdb

>>>pdb.run('boom.func(1, 0)')����# run/debug code

> (0)?()

(Pdb) b boom.func����������������� # set breakpoint

(Pdb) c��������������������������� # continue program

> boom.py(2)func()

->def func(x, y):

(Pdb) s��������������������������� # step 1 line

> boom.py(3)func()

-> return x / y

(Pdb) s

ZeroDivisionError: 'integer division or modulo'

> boom.py(3)func()

-> return x / y

(Pdb) where����������������������� # stack trace

� (1)?()

> boom.py(3)func()

-> return x / y

(Pdb) p y������������������������� # print variables

0

Inspecting name-spaces

♦ Python lookups use 3-scope rule: local, global, built-in

♦ locals(), globals(): return name-spaces as dictionaries

% python

>>> def func(x):

...���� a = 1

...���� print locals()��������������� # on function call

...���� print globals().keys()

...

>>> class klass:

...���� def __init__(self):

...�������� print locals()����������� # on instance creation

...�������� print globals().keys()

...���� print locals()��������������� # on class creation

...���� print globals().keys()

...

{'__init__': <function __init__ at 76ed00>}

['__builtins__', '__name__', 'func', '__doc__']

>>> func(1)

{'a': 2, 'x': 1}

['__builtins__', '__name__', 'func', 'klass', '__doc__']

>>> x = klass()

{'self': <klass instance at 76f8d0>, 'arg': None}

['__builtins__', '__name__', 'func', 'klass', '__doc__']

>>> def nester(L, M, N):

...���� class nested:�������������� # assigns class to name

...�������� def __init__(self):

...������������ pass

...�������� print locals()��������� # local=class global=mod

...�������� print globals().keys()� # no access to L/M/N!

...���� return nested���������������

...

>>> nester(1, 2, 3)

{'__init__': <function __init__ at 761e30>}

['__doc__', 'nester', '__name__', 'x', 'func', 'klass',...]

<class nested at 762960>

Dynamic coding tools

apply �� [nowfunc(*args)] runs functions with argument tuples

eval ���� evaluates a Python expression code-string

exec ���� runs a Python statement code-string (3.X: exec())

getattr fetches an object�s attribute by name string

♦ Supports run-time program construction

♦ Supports embedding Python in Python

Basic usage

>>> x = "2 ** 5"

>>> a = eval(x)

>>> a

32

>>> exec "print a / 2"�������� # 3.X: exec('print(a / 2)')

16

>>> def echo(a, b, c): print a, b, c

...

>>> apply(echo, (1, 2, 3))���� # now: echo(*(1, 2, 3))

1 2 3

>>> import string

>>> getattr(string, "uppercase")

'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

>>> D = {}

>>> exec "import math\nx = math.pi" in D, D�� # 3.X exec()

>>> D['x']

3.14159265359

Example

♦ Import module by name, run function by name/args

♦ Runs:� [ message.printer(�sir�, �robin�) ]

♦ Also see:�newer __import__ function

♦ Preview: will revisit model to embed Python in C

file: message.py

def printer(str1, str2):

��� return 'brave', str1, str2

file: dynamic.py

def runFunction(moduleName, functionName, argsTuple):

��� exec 'import ' + moduleName

��� module = eval(moduleName)

��� function = getattr(module, functionName)

��� return function(*argsTuple)

if__name__ == '__main__':

��� from sys import argv

��� print runFunction(argv[1], argv[2], tuple(argv[3:]))

Command line

% python dynamic.py message printer sir robin

('brave', 'sir', 'robin')

Timing and profiling Python programs

♦ _time_module contains C library type tools

♦ Useful for performance tweaking (along with profiler)

♦ Warning: be careful to compare apples to apples!

→ See also newer �timeit� module: automated, portable timing tools

>>> import timeit

>>> min(timeit.repeat(stmt="[x ** 2 for x in range(1000)]", number=1000, repeat=5))

0.5062382371756811

c:\code> python -m timeit-n 1000 -r 5 "[x ** 2 for x in range(1000)]"

1000 loops, best of 5: 505 usecper loop

Example: inline stack alternatives

♦ List based stacks

['spam0', 'spam1', 'spam2']� ←top

● Use list in-place changes: append/del

● Lists resized on demand: grown in increments

♦ Tuple-pair based stacks

_top_→� ('spam2', ('spam1', ('spam0', None)))

● Use tuple packing/unpacking assignments

● Build a tree of 2-item tuples: (item, tree)

● Like Lisp �cons� cells/linked lists: avoids copies

file: testinline.py

#!/opt/local/bin/python

import time

from sys import argv, exit

numtests= 20

try:

��� pushes, pops = eval(argv[1]), eval(argv[2])

except:

��� print 'usage: testinline.py '; exit(1)

deftest(reps, func):

��� start_cpu �= time.clock()

��� for i in xrange(reps):���������������# call N times

������� x = func()

���return time.clock() - start_cpu

definline1():��������������������������� # builtin lists

��� x = []

��� for i in range(pushes): x.append('spam' + `i`)

��� for i in range(pops):�� del x[-1]

definline2():��������������������������� # builtin tuples

��� x = None

��� for i in range(pushes): x = ('spam' + `i`, x)

��� for i in range(pops):�� (top, x) = x

print 'lists: ', test(numtests, inline1)� # run 20 times

print 'tuples:', test(numtests, inline2)

Results (on an ancient machine�)

% testinline.py 500 500���� --20*(500 pushes + 500 pops)

lists:� 0.77��������������� --lists: append/del

tuples: 0.43��������������� --tuples: pack/unpack

% testinline.py 1000 1000�� --20K pushes + 20K pops

lists:� 1.54

tuples: 0.87

% testinline.py 200 200

lists:� 0.31

tuples: 0.17

% testinline.py 5000 5000

lists:� 7.72

tuples: 4.5

Related Modules

datetime

>>> from datetimeimport datetime, timedelta

>>> x = datetime(2004, 11, 21)

>>> y = datetime(2005, 3, 19)

>>>

>>> y - x

datetime.timedelta(118)

>>>

>>> x + timedelta(30)

datetime.datetime(2004, 12, 21, 0, 0)

profile

● Run as _script_or interactive, like pdb debugger

As script python -m profile script.py

● Warning: don�t run at IDLE prompt (too much data)!

● cProfile: more efficient version in 2.5+

● pstats to report on results later

● Optimizing: profile, time, shedskin/psyco, move to C

>>> import profile

>>> profile.run('import test1')

�������� 35 function calls in 0.027 CPU seconds

�� Ordered by: standard name

�� ncalls� tottime� percall� cumtime� percall filename:lineno(function)

������ 16���0.001��� 0.000��� 0.001���0.000 :0(range)

������� 1���0.005��� 0.005��� 0.005���0.005 :0(setprofile)

������� 1���0.002��� 0.002��� 0.022���0.022 :1(?)

������� 1���0.000��� 0.000��� 0.027���0.027 profile:0(import test1)

������� 0���0.000������������ 0.000��������� profile:0(profiler)

������� 1���0.000��� 0.000��� 0.020���0.020 test1.py:2(?)

������ 15���0.019��� 0.001��� 0.020���0.001 test1.py:2(myfun)

Example: timing iteration alternatives

File types and packaging options

Byte code

● Modules compiled to portable byte-code on import: .pyc

● compileall module forces imports, to make .pyc�s

● .pyo files created and run with �O command-line flag (removed in 3.5!)

Frozen Binaries

● Package byte-code + Python in an executable

● Don�t require Python to be installed

● Protect your program code

Other options

● Import hooks support zip files, decryption, etc.

● Pickler converts objects to/from text stream (serializer)

Format Medium
Source files .py files, scripts
Source files, no console .pyw files (Windows,GUI)
Compiled byte-code files .pyc files, .pyo files(1.5 ~�3.4)
C extensions on Windows .pyd� (a .dll with init function)
Encrypted byte-code files Import hooks, PyCrypto
Frozen binaries, self-installers Py2Exe, PyInstaller,cx_freeze
distutils (see below), pip (newer) Setup.py installation scripts
Zip files of modules Auto in 2.4+ (zipimport 2.3+)
Pickled objects raw objects
Embedding mediums databases, etc.
Jython: Java bytecode network downloads, etc.

Development tools for larger projects

PyDoc Displaying docstrings, program structure
PyChecker Pre-run error checking (a �lint� for Python)
PyUnit Unit testing framework (a.k.a. unittest)
Doctest docstring-based regression test system
IDEs IDLE, Komodo, PythonWin,PythonWorks
Profilers profile, hotshot
Debuggers pdb, IDLE point-and-click, print
Optimization Psyco, .pyo bytecode, C extensions, SWIG
Packaging Py2Exe, Installer, Freeze (above)
Distutils packaging, install, build script system
Language tools module packages, private attributes, class exceptions, __name__==__main__, docstrings

Testing tools in the standard library

See also third-party testing tools, such as Nose

Simplest convention

if __name__ == '__main__':

��� unit test code here...

doctest module

● automates interactive session

● regression test system

# file spams.py

"""

This module works as follows:

>>> spams(3)

'spamspamspam'

>>> shrubbery()

'spamspamspamspam!!!'

"""

def spams(N):

��� return 'spam' * N

def shrubbery():

��� return spams(4) + '!!!'

if __name__ == '__main__':

��� import doctest

��� doctest.testmod()

C:\Python25>python spams.py -v

Trying:

��� spams(3)

Expecting:

��� 'spamspamspam'

ok

Trying:

��� shrubbery()

Expecting:

��� 'spamspamspamspam!!!'

ok

2 items had no tests:

��� __main__.shrubbery

��� __main__.spams

1 items passed all tests:

�� 2 tests in __main__

2 tests in 3 items.

2 passed and 0 failed.

Test passed.

unittest module (PyUnit)

● class structure for unit test code

● See library manual: test suites, �

import random

import unittest

class TestSequenceFunctions(unittest.TestCase):

���

��� def setUp(self):

������� self.seq = range(10)

��� def testshuffle(self):

������� # make sure the shuffled sequence does not lose any elements

������� random.shuffle(self.seq)

������� self.seq.sort()

������� self.assertEqual(self.seq, range(10))

��� def testchoice(self):

������� element = random.choice(self.seq)

������� self.assert_(element in self.seq)

��� def testsample(self):

������� self.assertRaises(ValueError, random.sample, self.seq, 20)

������� for element in random.sample(self.seq, 5):

����������� self.assert_(element in self.seq)

if __name__ == '__main__':

��� unittest.main()

Distutils: auto-install/build utility

See also more recent �pip� installer regime, and the PyPI site

# setup.py

from distutils.coreimport setup

setup(name='foo',

�����version='1.0',

����� py_modules=['foo'],

����� )

# Usage

python setup.py sdist���������� # make source distribution

python setup.py install�������� # install the system

python setup.py bdist_wininst�� # make Windows exe installer

python setup.py bdist_rpm������ # make Linux RPM installer

python setup.py register������� # register with PyPIsite

# setup.py for C extension modules

from distutils.coreimport setup, Extension

setup(name='foo',

�����version='1.0',

����� ext_modules=[Extension('foo', ['foo.c'])],

����� )

Summary: Python tool-set layers

♦ Built-ins

● Lists, dictionaries, strings, library modules, etc.

● High-level tools for simple, fast programming

������

♦ Python extensions

● Functions, classes, modules

● For adding extra features, and new object types

������

♦ C extensions

● C modules, C types

● For integrating external systems, optimizing components, customization

Lab Session 7

Click here to go to lab exercises

Click here to go to exercise solutions

Click here to go to solution source files

Click here to go to lecture example files