Skip to main content
Python
                             Web 2.0



                               QCon Beijing 2010

http://www.flickr.com/photos/arnolouise/2986467632/
About Me
• Python
• 2002             Python
• 2004
  Python
• http://www.douban.com/
  people/hongqn/
• hongqn@douban.com
• http://twitter.com/hongqn
Python
•   Python is a programming language that lets you
    work more quickly and integrate your systems more
    effectively. You can learn to use Python and see
    almost immediate gains in productivity and lower
    maintenance costs. (via http://python.org/)
Languages in
              C
             27%


                   Javascript
                      12%

                                C++
    Python                      3%
     58%
                            (Pyrex/R/Erlang/Go/Shell)
                                    1%
Why Python?
• Hello World: 1
• Hello World: 1
•            :1
• Hello World: 1
•            :1
•         :1
• Hello World: 1
•            :1
•         :1
•         :3
: 13
: 13
import os
from collections import defaultdict

d = defaultdict(int)

for dirpath, dirnames, filenames in os.walk('.'):
    for filename in filenames:
        path = os.path.join(dirpath, filename)
        ext = os.path.splitext(filename)[1]
        d[ext] += len(list(open(path)))

for ext, n_lines in d.items():
    print ext, n_lines
•
• Pythonic
•
    1. svn ci
    2. svn up
    3. restart
• Web
•
•
•
• Battery Included:             200+
• PyPI: 9613 packages currently
• /            /    /     /         /   /
          /...
• easily extensible
Python
Python
Python

Just kidding :-p
Web Server
Web Server
• python -m SimpleHTTPServer
Web Server
• python -m SimpleHTTPServer
web.py                http://webpy.org/

import web

urls = (
    '/(.*)', 'hello'
)
app = web.application(urls, globals())

class hello:
    def GET(self, name):
        if not name:
             name = 'World'
        return 'Hello, ' + name + '!'

if __name__ == "__main__":
    app.run()
Flask       http://flask.pocoo.org/




import flask import Flask
app = Flask(__name__)

@app.route("/<name>")
def hello(name):
    if not name:
        name = 'World'
    return 'Hello, ' + name + '!'

if __name__ == "__main__":
    app.run()
WSGI
   http://www.python.org/dev/peps/pep-0333/
Why so many Python
  web frameworks?
• Because you can write your own
  framework in 3 hours and a total of 60
  lines of Python code.
• http://bitworking.org/news/
  Why_so_many_Python_web_frameworks
doctest
def cube(x):
    """
    >>> cube(10)
    1000
    """
    return x * x

def _test():
    import doctest
    doctest.testmod()

if __name__ == "__main__":
    _test()
nose    http://somethingaboutorange.com/mrl/projects/nose/




from cube import cube

def test_cube():
    result = cube(10)
    assert result == 1000
numpy           http://numpy.scipy.org/




>>> from numpy import *
>>> A = arange(4).reshape(2, 2)
>>> A
array([[0, 1],
       [2, 3]])
>>> dot(A, A.T)
array([[ 1, 3],
       [ 3, 13]])
ipython          http://numpy.scipy.org/




$ ipython -pylab
In [1]: X = frange(0, 10, 0.1)
In [2]: Y = [sin(x) for x in X]
In [3]: plot(X, Y)
ipython          http://numpy.scipy.org/




$ ipython -pylab
In [1]: X = frange(0, 10, 0.1)
In [2]: Y = [sin(x) for x in X]
In [3]: plot(X, Y)
virtualenv            http://virtualenv.openplans.org/




                                python

$ python go-pylons.py --no-site-packages mydevenv
$ cd mydevenv
$ source bin/activate
(mydevenv)$ paster create -t new9 helloworld
Pyrex/Cython

cdef extern from "math.h"
    double sin(double)

cdef double f(double x):
    return sin(x*x)
Pythonic
>>> import this
The Zen of Python, by Tim Peters         http://bit.ly/pyzencn


Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to
break the rules.
                                          
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.               
In the face of ambiguity, refuse the
temptation to guess.
There should be one-- and
preferably only one --obvious way
to do it.
Although that way may not be           Python
obvious at first unless you're Dutch.    
Now is better than never.
Although never is often better than
*right* now.                            
If the implementation is hard to
explain, it's a bad idea.
If the implementation is easy to        
explain, it may be a good idea.
Namespaces are one honking great
idea -- let's do more of those!
Simple is better than
       complex
class HelloWorld
{
        public static void main(String args[])
        {
           System.out.println("Hello World!");
        }
}
Simple is better than
      complex

    print "Hello World!"
Readability counts
Readability counts

•           {}   end
Readability counts

•                  {}   end
•                 (except "@" for
    decorators)
Readability counts

•                    {}   end
•                  (except "@" for
    decorators)

if limit is not None and len(ids)>limit:
    ids = random.sample(ids, limit)
TOOWTDI
• There (should be) Only One Way To Do It.
• vs. Perlish TIMTOWTDI (There Is More
  Than One Way To Do It)
TOOWTDI
 • There (should be) Only One Way To Do It.
 • vs. Perlish TIMTOWTDI (There Is More
    Than One Way To Do It)

a = [1, 2, 3, 4, 5]
b = []
for i in range(len(a)):
    b.append(a[i]*2)
TOOWTDI
 • There (should be) Only One Way To Do It.
 • vs. Perlish TIMTOWTDI (There Is More
    Than One Way To Do It)

a = [1, 2, 3, 4, 5]
b = []
for i in range(len(a)):
    b.append(a[i]*2)
TOOWTDI
 • There (should be) Only One Way To Do It.
 • vs. Perlish TIMTOWTDI (There Is More
    Than One Way To Do It)

a = [1, 2, 3, 4, 5]       b = []
b = []                    for x in a:
for i in range(len(a)):
                              b.append(x*2)
    b.append(a[i]*2)
TOOWTDI
 • There (should be) Only One Way To Do It.
 • vs. Perlish TIMTOWTDI (There Is More
    Than One Way To Do It)

a = [1, 2, 3, 4, 5]       b = []
b = []                    for x in a:
for i in range(len(a)):
                              b.append(x*2)
    b.append(a[i]*2)
TOOWTDI
• There (should be) Only One Way To Do It.
• vs. Perlish TIMTOWTDI (There Is More
  Than One Way To Do It)



     b = [x*2 for x in a]
http://twitter.com/robbinfan/status/9879724095




http://twitter.com/hongqn/status/9883515681
Python                                                            C


http://www.flickr.com/photos/nicksieger/281055485/   http://www.flickr.com/photos/nicksieger/281055530/
Ruby



http://www.flickr.com/photos/nicksieger/280661836/
Java




http://www.flickr.com/photos/nicksieger/280662707/
Python
• svn
• svn
•       (   list)
• svn
•           (   list)
•       +
• svn
•                    (   list)
•       +
•           parser
config.py
MEMCACHED_ADDR = ['localhost:11211']

from local_config import *
config.py
MEMCACHED_ADDR = ['localhost:11211']

from local_config import *




                                       local_config.py
                                   MEMCACHED_ADDR = [
                                       'frodo:11211',
                                       'sam:11211',
                                       'pippin:11211',
                                       'merry:11211',
                                   ]
config.py
MEMCACHED_ADDR = ['localhost:11211']

from local_config import *




                    .py                local_config.py
            exec                   MEMCACHED_ADDR = [
                                       'frodo:11211',
                                       'sam:11211',
                                       'pippin:11211',
                                       'merry:11211',
                                   ]
•
class GroupUI(object):
    def new_topic(self, request):
        if self.group.can_post(request.user):
            return new_topic_ui(self.group)
        else:
            request.response.set_status(403, "Forbidden")
            return error_403_ui(msg="                 ")

    def join(self, request):
        if self.group.can_join(request.user):
        ...

class Group(object):
    def can_post(self, user):
        return self.group.has_member(user)

    def can_join(self, user):
        return not self.group.has_banned(user)
class GroupUI(object):
    @check_permission('post', msg="               ")
    def new_topic(self, request):
        return new_topic_ui(self.group)

    @check_permission('join', msg="          ")
    def join(self, request):
        ...

class Group(object):
    def can_post(self, user):
        return self.group.has_member(user)

    def can_join(self, user):
        return not self.group.has_banned(user)
decorator
def print_before_exec(func):
    def _(*args, **kwargs):
        print "decorated"
        return func(*args, **kwargs)
    return _

@print_before_exec
def double(x):
    print x*2

double(10)
decorator
def print_before_exec(func):
    def _(*args, **kwargs):
        print "decorated"
        return func(*args, **kwargs)
    return _
                                       decorated
@print_before_exec
def double(x):                         20
    print x*2

double(10)
class check_permission(object):
    def __init__(self, action, msg=None):
        self.action = action
        self.msg = msg

   def __call__(self, func):
       def _(ui, req, *args, **kwargs):
           f = getattr(ui.perm_obj, 'can_' + self.action)
           if f(req.user):
                return func(ui, *args, **kwargs)
           raise BadPermission(ui.perm_obj, self.action,
                                self.msg)
       return _
class check_permission(object):
    def __init__(self, action, msg=None):
        self.action = action
        self.msg = msg

    def __call__(self, func):
        def _(ui, req, *args, **kwargs):
            f = getattr(ui.perm_obj, 'can_' + self.action)
            if f(req.user):
                 return func(ui, *args, **kwargs)
            raise BadPermission(ui.perm_obj, self.action,
                                 self.msg)
        return _
class check_permission(object):
    def __init__(self, action, msg=None):
        self.action = action
        self.msg = msg

   def __call__(self, func):
       def _(ui, req, *args, **kwargs):
           f = getattr(ui.perm_obj, 'can_' + self.action)
           if f(req.user):
               return func(ui, *args, **kwargs)
           raise BadPermission(ui.perm_obj, self.action,
                               self.msg)
       return _
class check_permission(object):
    def __init__(self, action, msg=None):
        self.action = action
        self.msg = msg

   def __call__(self, func):
       def _(ui, req, *args, **kwargs):
           f = getattr(ui.perm_obj, 'can_' + self.action)
           if f(req.user):
                return func(ui, *args, **kwargs)
           raise BadPermission(ui.perm_obj, self.action,
                                self.msg)
       return _
class check_permission(object):
    def __init__(self, action, msg=None):
        self.action = action
        self.msg = msg

   def __call__(self, func):
       def _(ui, req, *args, **kwargs):
           f = getattr(ui.perm_obj, 'can_' + self.action)
           if f(req.user):
                return func(ui, *args, **kwargs)
           raise BadPermission(ui.perm_obj, self.action,
                                self.msg)
       return _
class check_permission(object):
    def __init__(self, action, msg=None):
        self.action = action
        self.msg = msg

   def __call__(self, func):
       def _(ui, req, *args, **kwargs):
           f = getattr(ui.perm_obj, 'can_' + self.action)
           if f(req.user):
                return func(ui, *args, **kwargs)
           raise BadPermission(ui.perm_obj, self.action,
                                self.msg)
       return _
class GroupUI(object):
    @check_permission('post', msg="               ")
    def new_topic(self, request):
        return new_topic_ui(self.group)

    @check_permission('join', msg="          ")
    def join(self, request):
        ...

class Group(object):
    def can_post(self, user):
        return self.group.has_member(user)

    def can_join(self, user):
        return not self.group.has_banned(user)
•
def send_notification_mail(email, subject, body):
    msg = MSG_SEND_MAIL + '0' + email + '0' + subject + '0' + body
    mq.put(msg)



def async_worker():
    msg = mq.get()
    msg = msg.split('0')
    cmd = msg[0]
    if cmd == MSG_SEND_MAIL:
        email, subject, body = msg[1:]
        fromaddr = 'no-reply@douban.com'
        email_body = make_email_body(fromaddr, email, subject, body)
        smtp = smtplib.SMTP('mail')
        smtp.sendmail(fromaddr, email, email_body)
    elif cmd == MSG_xxxx:
        ...
    elif cmd == MSG_yyyy:
        ...
@async
def send_notification_mail(email, subject, body):
    fromaddr = 'no-reply@douban.com'
    email_body = make_email_body(fromaddr, email, subject,
body)
    smtp = smtplib.SMTP('mail')
    smtp.sendmail(fromaddr, email, email_body)
def async(func):
    mod = sys.modules[func.__module__]
    fname = 'origin_' + func.__name__
    mod.__dict__[fname] = func
    def _(*a, **kw):
        body = cPickle.dumps((mod.__name__, fname, a, kw))
        mq.put(body)
    return _


def async_worker():
    modname, fname, a, kw = cPickle.loads(mq.get())
    __import__(modname)
    mod = sys.modules[modname]
    mod.__dict__[fname](*a, **kw)
def async(func):
    mod = sys.modules[func.__module__]
    fname = 'origin_' + func.__name__
    mod.__dict__[fname] = func
    def _(*a, **kw):
        body = cPickle.dumps((mod.__name__, fname, a, kw))
        mq.put(body)
    return _


def async_worker():
    modname, fname, a, kw = cPickle.loads(mq.get())
    __import__(modname)
    mod = sys.modules[modname]
    mod.__dict__[fname](*a, **kw)
def async(func):
    mod = sys.modules[func.__module__]
    fname = 'origin_' + func.__name__
    mod.__dict__[fname] = func
    def _(*a, **kw):
        body = cPickle.dumps((mod.__name__, fname, a, kw))
        mq.put(body)
    return _


def async_worker():
    modname, fname, a, kw = cPickle.loads(mq.get())
    __import__(modname)
    mod = sys.modules[modname]
    mod.__dict__[fname](*a, **kw)
def async(func):
    mod = sys.modules[func.__module__]
    fname = 'origin_' + func.__name__
    mod.__dict__[fname] = func
    def _(*a, **kw):
        body = cPickle.dumps((mod.__name__, fname, a, kw))
        mq.put(body)
    return _


def async_worker():
    modname, fname, a, kw = cPickle.loads(mq.get())
    __import__(modname)
    mod = sys.modules[modname]
    mod.__dict__[fname](*a, **kw)
def async(func):
    mod = sys.modules[func.__module__]
    fname = 'origin_' + func.__name__
    mod.__dict__[fname] = func
    def _(*a, **kw):
        body = cPickle.dumps((mod.__name__, fname, a, kw))
        mq.put(body)
    return _


def async_worker():
    modname, fname, a, kw = cPickle.loads(mq.get())
    __import__(modname)
    mod = sys.modules[modname]
    mod.__dict__[fname](*a, **kw)
def async(func):
    mod = sys.modules[func.__module__]
    fname = 'origin_' + func.__name__
    mod.__dict__[fname] = func
    def _(*a, **kw):
        body = cPickle.dumps((mod.__name__, fname, a, kw))
        mq.put(body)
    return _


def async_worker():
    modname, fname, a, kw = cPickle.loads(mq.get())
    __import__(modname)
    mod = sys.modules[modname]
    mod.__dict__[fname](*a, **kw)
def async(func):
    mod = sys.modules[func.__module__]
    fname = 'origin_' + func.__name__
    mod.__dict__[fname] = func
    def _(*a, **kw):
        body = cPickle.dumps((mod.__name__, fname, a, kw))
        mq.put(body)
    return _


def async_worker():
    modname, fname, a, kw = cPickle.loads(mq.get())
    __import__(modname)
    mod = sys.modules[modname]
    mod.__dict__[fname](*a, **kw)
def async(func):
    mod = sys.modules[func.__module__]
    fname = 'origin_' + func.__name__
    mod.__dict__[fname] = func
    def _(*a, **kw):
        body = cPickle.dumps((mod.__name__, fname, a, kw))
        mq.put(body)
    return _


def async_worker():
    modname, fname, a, kw = cPickle.loads(mq.get())
    __import__(modname)
    mod = sys.modules[modname]
    mod.__dict__[fname](*a, **kw)
• cache   (SQL,   , etc)
def get_latest_review_id():
    review_id = mc.get('latest_review_id')
    if review_id is None:
        review_id = exc_sql("select max(id) from review")
        mc.set('latest_review_id', review_id)
    return review_id
@cache('latest_review_id')
def get_latest_review_id():
    return exc_sql("select max(id) from review")
def cache(key):
    def deco(func):
        def _(*args, **kwargs):
            r = mc.get(key)
            if r is None:
                 r = func(*args, **kwargs)
                 mc.set(key, r)
            return r
        return _
    return deco
def cache(key):
    def deco(func):
        def _(*args, **kwargs):
            r = mc.get(key)
            if r is None:
                r = func(*args, **kwargs)
                mc.set(key, r)
            return r
        return _
    return deco
cache key

def get_review(id):
    key = 'review:%s' % id
    review = mc.get(key)
    if review is None: # cache miss
        id, author_id, text = exc_sql("select id, author_id,
text from review where id=%s", id)
        review = Review(id, author_id, text)
        mc.set(key, review)
    return review
cache key
                       decorator


@cache('review:{id}')
def get_review(id):
    id, author_id, text = exc_sql("select id, author_id,
text from review where id=%s", id)
    return Review(id, author_id, text)
def cache(key_pattern, expire=0):
    def deco(f):
        arg_names, varargs, varkw, defaults = inspect.getargspec(f)
        if varargs or varkw:
            raise Exception("not support varargs")
        gen_key = gen_key_factory(key_pattern, arg_names, defaults)

       def _(*a, **kw):
           key = gen_key(*a, **kw)
           r = mc.get(key)
           if r is None:
                r = f(*a, **kw)
                mc.set(key, r, expire)
           return r
       return _
   return deco
def cache(key_pattern, expire=0):
    def deco(f):
        arg_names, varargs, varkw, defaults = inspect.getargspec(f)
        if varargs or varkw:
            raise Exception("not support varargs")
        gen_key = gen_key_factory(key_pattern, arg_names, defaults)

       def _(*a, **kw):
           key = gen_key(*a, **kw)
           r = mc.get(key)
           if r is None:
                r = f(*a, **kw)
                mc.set(key, r, expire)
           return r
       return _
   return deco
def cache(key_pattern, expire=0):
    def deco(f):
        arg_names, varargs, varkw, defaults = inspect.getargspec(f)
        if varargs or varkw:
            raise Exception("not support varargs")
        gen_key = gen_key_factory(key_pattern, arg_names, defaults)

       def _(*a, **kw):
           key = gen_key(*a, **kw)
           r = mc.get(key)
           if r is None:
                r = f(*a, **kw)
                mc.set(key, r, expire)
           return r
       return _
   return deco
inspect.getargspec
>>> import inspect
>>> def f(a, b=1, c=2):
...     pass
...
>>> inspect.getargspec(f)
ArgSpec(args=['a', 'b', 'c'], varargs=None, keywords=None,
defaults=(1, 2))
>>>
>>>
>>> def f(a, b=1, c=2, *args, **kwargs):
...     pass
...
>>> inspect.getargspec(f)
ArgSpec(args=['a', 'b', 'c'], varargs='args', keywords='kwargs',
defaults=(1, 2))
def cache(key_pattern, expire=0):
    def deco(f):
        arg_names, varargs, varkw, defaults = inspect.getargspec(f)
        if varargs or varkw:
            raise Exception("not support varargs")
        gen_key = gen_key_factory(key_pattern, arg_names, defaults)

       def _(*a, **kw):
           key = gen_key(*a, **kw)
           r = mc.get(key)
           if r is None:
                r = f(*a, **kw)
                mc.set(key, r, expire)
           return r
       return _
   return deco
def cache(key_pattern, expire=0):
    def deco(f):
        arg_names, varargs, varkw, defaults = inspect.getargspec(f)
        if varargs or varkw:
            raise Exception("not support varargs")
        gen_key = gen_key_factory(key_pattern, arg_names, defaults)

       def _(*a, **kw):
           key = gen_key(*a, **kw)
           r = mc.get(key)
           if r is None:

                          hint:
                r = f(*a, **kw)
                mc.set(key, r, expire)
           return r        • str.format in python 2.6:
                                '{id}'.format(id=1) => '1'
       return _
   return deco             • dict(zip(['a', 'b', 'c'], [1, 2, 3]))
                                => {'a': 1, 'b': 2, 'c': 3}
def cache(key_pattern, expire=0):
    def deco(f):
        arg_names, varargs, varkw, defaults = inspect.getargspec(f)
        if varargs or varkw:
            raise Exception("not support varargs")
        gen_key = gen_key_factory(key_pattern, arg_names, defaults)

       def _(*a, **kw):
           key = gen_key(*a, **kw)
           r = mc.get(key)
           if r is None:

                          hint:
                r = f(*a, **kw)
                mc.set(key, r, expire)
           return r        • str.format in python 2.6:
                                '{id}'.format(id=1) => '1'
       return _
   return deco             • dict(zip(['a', 'b', 'c'], [1, 2, 3]))
                                => {'a': 1, 'b': 2, 'c': 3}