New_Project/┌─────virtualenv──────────┐
│ /bin: python2, pip │
│ /include │
│ /lib: Django 1.5, lxml │
└─────────────────────────┘
Old_Project/┌─────virtualenv──────────────────┐
│ /bin: python2, pip │
│ /include │
│ /lib: Django 1.4, BeautifulSoup │
└─────────────────────────────────┘
de421==2008
jplephem==1.1
numpy==1.7.1
sgp4==1.1
$ cd ~/project
$ virtualenv venv
$ venv/bin/pip install -r requirements.txt
Project sandboxes
return sorted(set(
student.surname for student in students
if not student.graduated
))
semester.txt students.txt
N N 1 N
⋮ ⋮
Smith CS101 Williams Sophmore
Johnson EE201 Johnson Junior
Williams PH131 Smith Freshman
Smith PH132 Jones Sophmore
Jones PH131 Brown Freshman
Brown EE201 ⋮
Williams CS101
⋮
for line in open('semester.txt'):
name, course = line.split()
for line in open('students.txt'):
name2, year = line.split()
if name == name2:
break
⋮
O(nm)
students = [line.split() for line
in open('students.txt')]
for line in open('semester.txt'):
name, course = line.split()
for name2, year in students:
if name == name2:
break
⋮
O(nm)
years = {}
for line in open('students.txt'):
name, year = line.split()
years[name] = year
students.txt
⋮
Williams Sophmore
Johnson Junior
Smith Freshman
⋮
Given our dictionary—
{'Williams': 'Sophmore',
'Johnson': 'Junior',
'Smith': 'Freshman',
⋮
—asking for a student takes constant time—
y = years['Johnson']
print y
# => 'Junior'
...
for line in open('semester.txt'):
name, course = line.split()
year = years[name] # the join!
...
semester.txt
⋮
Smith CS101
Johnson EE201
Williams PH131
Smith PH132
⋮
years = {}
for line in open('students.txt'):
name, year = line.split()
years[name] = year
...
for line in open('semester.txt'):
name, course = line.split()
year = years[name] # the join!
...
Hash Join
-> Seq scan on semester
-> Hash
-> Seq Scan on student
from collections import Counter, defaultdict
years = {}
for line in open('students.txt'):
name, year = line.split()
years[name] = year
enrollment = defaultdict(Counter)
for line in open('semester.txt'):
name, course = line.split()
year = years[name] # the join!
enrollment[course][year] += 1
{'EE220': {'Sophmore': 89, 'Junior': 12},
'CS125': {'Freshman': 198, 'Sophmore': 22},
'PH441': {'Junior': 8, 'Senior': 22},
⋮
points = [(3,4), (5,12), (15,8)]
for p in points:
print sqrt(p[0]**2 + p[1]**2)
# vs
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
points = [Point(3,4), Point(5,12), Point(15,8)]
for p in points:
print sqrt(p.x**2 + p.y**2)
Two variants
X = 0
Y = 1
points = [(3,4), (5,12), (15,8)]
for p in points:
print sqrt(p[X]**2 + p[Y]**2)
from collections import namedtuple
Point = namedtuple('Point', 'x y')
points = [Point(0,0), Point(3,0), Point(0,4)]
for p in points:
print sqrt(p.x**2 + p.y**2)
type(points) # => list? or PointSequence?
type(point) # => tuple? or Point?
but
p = (4, 5)
d = sqrt(p[0]**2 + p[1]**2 + p[2]**2)
# => IndexError: list index out of range
p = Point(4, 5)
d = sqrt(p.x**2 + p.y**2 + p.z**2)
# => AttributeError: no attribute 'z'
tuple list dict set
Powerful built-in data types
point = (3, 4)
point = Point(3, 4)
"""Alterative to:
points = [(3,4), (5,12), (15,8)]
"""
from numpy import array, sqrt
x = array([3, 5, 15])
y = array([4, 12, 8])
print sqrt(x*x + y*y)
# => [ 5. 13. 17.]
print sqrt(x*x + y*y)
# => [ 5. 13. 17.]
Vector math
def f(): def g(): def h():
... ... sys.exit()
g() h()
... ...
↖ ↖
def f(): def g(): def h():
... ... raise ValueError()
g() h()
... ...
↖ ↖
def f(): def g(): def h():
... ... raise ValueError()
... h()
try: ... # skipped
g()
except ValueError:
log('error')
... # not skipped!
@app.route('/<user_name>/<project_name>/')
@json_response
def project_page(user_name, project_name):
user = db_load(User, user_name)
if user is None:
return {'error': 'does_not_exist'}, 404
project = db_load(Project, user, project_name)
if project is None:
return {'error': 'does_not_exist'}, 404
...
class AppError(Exception): ...
class NotFoundError(AppError): ...
class PermissionError(AppError): ...
class DatabaseError(AppError): ...
class AuthError(AppError): ...
def db_load(cls, key):
...
if obj is None:
raise NotFoundError()
...
def exception_to_response(e):
if isinstance(e, NotFoundError):
name, code = 'not_found', 404
elif isinstance(e, PermissionError):
name, code = 'forbidden', 403
elif isinstance(e, DatabaseError):
name, code = 'unavailable', 503
elif isinstance(e, AuthError):
name, code = 'bad_auth', 401
else:
name, code = 'internal', 500
return {'error': name}, code
from functools import wraps
def catch_errors(view):
@wraps(view)
def wrapper(*args, **kw):
try:
return view(*args, **kw)
except AppError as e:
return exception_to_response(e)
return wrapper
@app.route('...')
@json_response
@catch_errors
def view(...):
...
@app.route('...')
@json_response
@catch_errors
def view(...):
user = get_row(user, name)
# => NotFoundError, DatabaseError
data = user.cloud_open(filename)
# => PermissionError
return {'name': name, 'data': data}, 200
flask.pocoo.org/docs/patterns/apierrors/
@app.errorhandler(DatabaseError)
@json_response
def handle_database_error(error):
return {'error': 'unavailable'}, 503
caveat
user = get_row(user, name)
data = user.cloud_open(filename)
return {'name': name, 'data': data}, 200
try:
user = get_row(user, name)
except NotFoundError:
user = None
try:
data = user.cloud_open(filename)
except PermissionError:
data = ''
...
There's a pattern for that
getattr(obj, 'a') # => AttributeError
getattr(obj, 'a', None) # => None
mydict['a'] # => KeyError
mydict.get('a', None) # => None
So your own calls can:
user = get_row(user, name, default=None)
conn = HTTPSConnection(
host='www.google.com',
key_file='/u/brandon/client.key',
cert_file='/u/brandon/client.crt',
)
with tempfile.NamedTemporaryFile() as f:
f.write(cert_pem + key_pem)
f.flush()
conn = HTTPSConnection(
host='www.google.com',
key_file=f.name,
cert_file=f.name,
)
Public Bug Tracker
http://bugs.python.org/issue16487
“Python 3.4”
class HTTPSConnection(HTTPConnection):
...
def __init__(self, ...
key_file=None, cert_file=None...):
...
self.key_file = key_file
self.cert_file = cert_file
def connect(self):
...
self.sock = ssl.wrap_socket(
sock, self.key_file, self.cert_file)
def wrap_socket(sock, keyfile=None,
certfile=None, ...
do_handshake_on_connect=True,
...):
return SSLSocket(sock, keyfile=keyfile,
certfile=certfile, ...
do_handshake_on_connect=...)
class SSLSocket(socket):
def __init__(
self, sock, keyfile=None, certfile=None,
... do_handshake_on_connect=True, ...):
...
self._sslobj = _ssl.sslwrap(self._sock,
server_side, keyfile, certfile, ...)
if do_handshake_on_connect:
self.do_handshake()
...
static PyObject *
PySSL_sslwrap(PyObject *self, PyObject *args)
{
...
return (PyObject *) newPySSLObject(
Sock, key_file, cert_file, ...);
}
static PyMethodDef PySSL_methods[] = {
{"sslwrap", PySSL_sslwrap,
METH_VARARGS, ssl_doc},
...
}
static PySSLObject *newPySSLObject
(... char *key_file, char *cert_file, ...)
{
...
if (key_file) {
...
ret = SSL_CTX_use_PrivateKey_file(
self->ctx, key_file, SSL_FILETYPE_PEM);
...
ret = SSL_CTX_use_certificate_chain_file(
self->ctx, cert_file);
...
}
return self;
An aside
in = BIO_new_mem_buf(data, len);
pkey = PEM_read_bio_PrivateKey(in, ...);
ret = SSL_CTX_use_PrivateKey(...);
in = BIO_new_mem_buf(data, len);
x = PEM_read_bio_X509(in, ...);
ret = SSL_CTX_use_certificate(ctx, x);
Complete Object Introspection
Code re-use!
┌module.py──────────────────┐
│ Python │
│ │
└─ctypes──cffi──────────────┘
↕
┌module.so──┐
↓ ↓ │ Python │ ← raw C
│ Extension │ ← Cython
| Module │ ← SWIG
└───────────┘
↕
┌library.so─────────────────┐
│ C library │
└───────────────────────────┘
Extensibility
class PySSLObject(ctypes.Structure):
_fields_ = [
('ob_refcnt', ctypes.c_int),
('ob_type', ctypes.c_void_p),
('Socket', ctypes.c_void_p),
('ctx', ctypes.c_void_p),
('ssl', ctypes.c_void_p),
]
def _bio(string):
bio = libeay.BIO_new_mem_buf(
string, len(string))
if not bio:
raise ss.SSLError(...)
return bio
def install_text_cert(conn, cert_text, key_text):
addr = id(conn.sock._sslobj)
ptype = ctypes.POINTER(PySSLObject)
obj = ctypes.cast(addr, ptype).contents
c = libeay.PEM_read_bio_X509(
_bio(cert_text), 0, 0, 0)
k = libeay.PEM_read_bio_PrivateKey(
_bio(key_text), 0, 0, 0)
libssl.SSL_CTX_use_certificate(obj.ctx, c)
libssl.SSL_CTX_use_PrivateKey(obj.ctx, k)
One last story
from timeit import timeit
SETUP = """
import re
search = re.compile(r"([a-z])(\1)").search
b1 = 'bubble'
bk = 'bubble' * 1000
"""
print timeit('search(b1)', SETUP, number=10000)
print timeit('search(bk)', SETUP, number=10000)
0.0149960517883
5.89959216118
/usr/lib/python2.7/timeit.py
→ ./timeit.py
—and added a print statement—
def inner(_it, _timer):
import re
search = re.compile(r"([a-z])(␁)").search
b1 = 'bubble'
bk = 'bubble' * 1000
_t0 = _timer()
for _i in _it:
search(bk)
_t1 = _timer()
return _t1 - _t0
from timeit import timeit
SETUP = """
import re
search = re.compile(r"([a-z])(\1)").search
b1 = 'bubble'
bk = 'bubble' * 1000
"""
print timeit('search(b1)', SETUP, number=10000)
print timeit('search(bk)', SETUP, number=10000)
Thank you very much!