月度归档:2013年03月

加速 python ,Ctypes的介绍

地址:http://www.oschina.net/translate/speeding-up-your-python-code?from=20130324

常规的这样:

 

>>> import random

>>> def generate(num):

while num:
yield random.randrange(10)
num -=1

>>> print(timeit.timeit(“sum(generate(999))”, setup=”from __main__ import generate”, number=1000))

2.5973080588

 

>>> import timeit
>>> from ctypes import cdll
>>> def generate_c(num):
libc=cdll.msvcrt
while num:
yield libc.rand() %10
num -=1
>>> print(timeit.timeit(“sum(generate_c(999))”, setup=”from __main__ import generate_c”, number=1000))
1.11328007418

 

明显快了一点。

pyramid 单文件例子

http://docs.pylonsproject.org/projects/pyramid_tutorials/en/latest/single_file_tasks/single_file_tasks.html

pyramid 单文件例子,留档学习,tasks.py

import os
import logging
import sqlite3

from pyramid.config import Configurator
from pyramid.events import NewRequest
from pyramid.events import subscriber
from pyramid.events import ApplicationCreated
from pyramid.httpexceptions import HTTPFound
from pyramid.session import UnencryptedCookieSessionFactoryConfig
from pyramid.view import view_config

from wsgiref.simple_server import make_server

logging.basicConfig()
log = logging.getLogger(__file__)

here = os.path.dirname(os.path.abspath(__file__))

# views
@view_config(route_name='list', renderer='list.mako')
def list_view(request):
    rs = request.db.execute("select id, name from tasks where closed = 0")
    tasks = [dict(id=row[0], name=row[1]) for row in rs.fetchall()]
    return {'tasks': tasks}

@view_config(route_name='new', renderer='new.mako')
def new_view(request):
    if request.method == 'POST':
        if request.POST.get('name'):
            request.db.execute(
                'insert into tasks (name, closed) values (?, ?)',
                [request.POST['name'], 0])
            request.db.commit()
            request.session.flash('New task was successfully added!')
            return HTTPFound(location=request.route_url('list'))
        else:
            request.session.flash('Please enter a name for the task!')
    return {}

@view_config(route_name='close')
def close_view(request):
    task_id = int(request.matchdict['id'])
    request.db.execute("update tasks set closed = ? where id = ?",
                       (1, task_id))
    request.db.commit()
    request.session.flash('Task was successfully closed!')
    return HTTPFound(location=request.route_url('list'))

@view_config(context='pyramid.exceptions.NotFound', renderer='notfound.mako')
def notfound_view(self):
    return {}

# subscribers
@subscriber(NewRequest)
def new_request_subscriber(event):
    request = event.request
    settings = request.registry.settings
    request.db = sqlite3.connect(settings['db'])
    request.add_finished_callback(close_db_connection)

def close_db_connection(request):
    request.db.close()

@subscriber(ApplicationCreated)
def application_created_subscriber(event):
    log.warn('Initializing database...')
    with open(os.path.join(here, 'schema.sql')) as f:
        stmt = f.read()
        settings = event.app.registry.settings
        db = sqlite3.connect(settings['db'])
        db.executescript(stmt)
        db.commit()

if __name__ == '__main__':
    # configuration settings
    settings = {}
    settings['reload_all'] = True
    settings['debug_all'] = True
    settings['mako.directories'] = os.path.join(here, 'templates')
    settings['db'] = os.path.join(here, 'tasks.db')
    # session factory
    session_factory = UnencryptedCookieSessionFactoryConfig('itsaseekreet')
    # configuration setup
    config = Configurator(settings=settings, session_factory=session_factory)
    # routes setup
    config.add_route('list', '/')
    config.add_route('new', '/new')
    config.add_route('close', '/close/{id}')
    # static view setup
    config.add_static_view('static', os.path.join(here, 'static'))
    # scan for @view_config and @subscriber decorators
    config.scan()
    # serve app
    app = config.make_wsgi_app()
    server = make_server('0.0.0.0', 8080, app)
    server.serve_forever()

web.py解析 续1

昨日看到httpserver.py这里:

    global server
    func = StaticMiddleware(func)
    func = LogMiddleware(func)
    server = WSGIServer(server_address, func)
于是在下面看到StaticMiddleware和LogMiddleware的定义:
class StaticMiddleware:
    “””WSGI middleware for serving static files.”””
    def __init__(self, app, prefix=’/static/’):
        self.app = app
        self.prefix = prefix
    def __call__(self, environ, start_response):
        path = environ.get(‘PATH_INFO’, ”)
        path = self.normpath(path)
        if path.startswith(self.prefix):
            return StaticApp(environ, start_response)
        else:
            return self.app(environ, start_response)
    def normpath(self, path):
        path2 = posixpath.normpath(urllib.unquote(path))
        if path.endswith(“/”):
            path2 += “/”
        return path2
class LogMiddleware:
    “””WSGI middleware for logging the status.”””
    def __init__(self, app):
        self.app = app
        self.format = ‘%s – – [%s] “%s %s %s” – %s’
        from BaseHTTPServer import BaseHTTPRequestHandler
        import StringIO
        f = StringIO.StringIO()
        class FakeSocket:
            def makefile(self, *a):
                return f
        # take log_date_time_string method from BaseHTTPRequestHandler
        self.log_date_time_string = BaseHTTPRequestHandler(FakeSocket(), None, None).log_date_time_string
    def __call__(self, environ, start_response):
        def xstart_response(status, response_headers, *args):
            out = start_response(status, response_headers, *args)
            self.log(status, environ)
            return out
        return self.app(environ, xstart_response)
    def log(self, status, environ):
        outfile = environ.get(‘wsgi.errors’, web.debug)
        req = environ.get(‘PATH_INFO’, ‘_’)
        protocol = environ.get(‘ACTUAL_SERVER_PROTOCOL’, ‘-‘)
        method = environ.get(‘REQUEST_METHOD’, ‘-‘)
        host = “%s:%s” % (environ.get(‘REMOTE_ADDR’,’-‘),
                          environ.get(‘REMOTE_PORT’,’-‘))
        time = self.log_date_time_string()
        msg = self.format % (host, time, protocol, method, req, status)
        print >> outfile, utils.safestr(msg)
顺便发现看代码的一个好网站:
比如查抄web.py 3.7版本里面所有的类,直接看:
继续 server = WSGIServer(server_address, func)
WSGIServer在这里定义:
00163 def WSGIServer(server_address, wsgi_app):
00164     """Creates CherryPy WSGI server listening at `server_address` to serve `wsgi_app`.
00165     This function can be overwritten to customize the webserver or use a different webserver.
00166     """
00167     import wsgiserver
00168
00169     # Default values of wsgiserver.ssl_adapters uses cherrypy.wsgiserver
00170     # prefix. Overwriting it make it work with web.wsgiserver.
00171     wsgiserver.ssl_adapters = {
00172         'builtin': 'web.wsgiserver.ssl_builtin.BuiltinSSLAdapter',
00173         'pyopenssl': 'web.wsgiserver.ssl_pyopenssl.pyOpenSSLAdapter',
00174     }
00175
00176     server = wsgiserver.CherryPyWSGIServer(server_address, wsgi_app, server_name="localhost")
00177
00178     def create_ssl_adapter(cert, key):
00179         # wsgiserver tries to import submodules as cherrypy.wsgiserver.foo.
00180         # That doesn't work as not it is web.wsgiserver.
00181         # Patching sys.modules temporarily to make it work.
00182         import types
00183         cherrypy = types.ModuleType('cherrypy')
00184         cherrypy.wsgiserver = wsgiserver
00185         sys.modules['cherrypy'] = cherrypy
00186         sys.modules['cherrypy.wsgiserver'] = wsgiserver
00187
00188         from wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
00189         adapter = pyOpenSSLAdapter(cert, key)
00190
00191         # We are done with our work. Cleanup the patches.
00192         del sys.modules['cherrypy']
00193         del sys.modules['cherrypy.wsgiserver']
00194
00195         return adapter
00196
00197     # SSL backward compatibility
00198     if (server.ssl_adapter is None and
00199         getattr(server, 'ssl_certificate', None) and
00200         getattr(server, 'ssl_private_key', None)):
00201         server.ssl_adapter = create_ssl_adapter(server.ssl_certificate, server.ssl_private_key)
00202
00203     server.nodelay = not sys.platform.startswith('java') # TCP_NODELAY isn't supported on the JVM
00204     return server
import wsgiserver这里,就是用的cherry框架! server = wsgiserver.CherryPyWSGIServer(server_address, wsgi_app, server_name="localhost") ,.CherryPyWSGIServer类定义如下:
01978 class CherryPyWSGIServer(HTTPServer):
01979
01980     wsgi_version = (1, 0)
01981
01982     def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None,
01983                  max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
01984         self.requests = ThreadPool(self, min=numthreads or 1, max=max)
01985         self.wsgi_app = wsgi_app
01986         self.gateway = wsgi_gateways[self.wsgi_version]
01987
01988         self.bind_addr = bind_addr
01989         if not server_name:
01990             server_name = socket.gethostname()
01991         self.server_name = server_name
01992         self.request_queue_size = request_queue_size
01993
01994         self.timeout = timeout
01995         self.shutdown_timeout = shutdown_timeout
01996         self.clear_stats()
01997
01998     def _get_numthreads(self):
01999         return self.requests.min
02000     def _set_numthreads(self, value):
02001         self.requests.min = value
02002     numthreads = property(_get_numthreads, _set_numthreads)

其实wsgiserver的init文档里,已经简单说明怎么使用cherry了:

00001 """A high-speed, production ready, thread pooled, generic HTTP server.
00002
00003 Simplest example on how to use this module directly
00004 (without using CherryPy's application machinery)::
00005
00006     from cherrypy import wsgiserver
00007
00008     def my_crazy_app(environ, start_response):
00009         status = '200 OK'
00010         response_headers = [('Content-type','text/plain')]
00011         start_response(status, response_headers)
00012         return ['Hello world!']
00013
00014     server = wsgiserver.CherryPyWSGIServer(
00015                 ('0.0.0.0', 8070), my_crazy_app,
00016                 server_name='www.cherrypy.example')
00017     server.start()
00018
00019 The CherryPy WSGI server can serve as many WSGI applications
00020 as you want in one instance by using a WSGIPathInfoDispatcher::
00021
00022     d = WSGIPathInfoDispatcher({'/': my_crazy_app, '/blog': my_blog_app})
00023     server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), d)
00024
00025 Want SSL support? Just set server.ssl_adapter to an SSLAdapter instance.
00026
00027 This won't call the CherryPy engine (application side) at all, only the
00028 HTTP server, which is independent from the rest of CherryPy. Don't
00029 let the name "CherryPyWSGIServer" throw you; the name merely reflects
00030 its origin, not its coupling.
00031
00032 For those of you wanting to understand internals of this module, here's the
00033 basic call flow. The server's listening thread runs a very tight loop,
00034 sticking incoming connections onto a Queue::
00035
00036     server = CherryPyWSGIServer(...)
00037     server.start()
00038     while True:
00039         tick()
00040         # This blocks until a request comes in:
00041         child = socket.accept()
00042         conn = HTTPConnection(child, ...)
00043         server.requests.put(conn)
00044
00045 Worker threads are kept in a pool and poll the Queue, popping off and then
00046 handling each connection in turn. Each connection can consist of an arbitrary
00047 number of requests and their responses, so we run a nested loop::
00048
00049     while True:
00050         conn = server.requests.get()
00051         conn.communicate()
00052         ->  while True:
00053                 req = HTTPRequest(...)
00054                 req.parse_request()
00055                 ->  # Read the Request-Line, e.g. "GET /page HTTP/1.1"
00056                     req.rfile.readline()
00057                     read_headers(req.rfile, req.inheaders)
00058                 req.respond()
00059                 ->  response = app(...)
00060                     try:
00061                         for chunk in response:
00062                             if chunk:
00063                                 req.write(chunk)
00064                     finally:
00065                         if hasattr(response, "close"):
00066                             response.close()
00067                 if req.close_connection:
00068                     return
00069 """
Run the server forever.在httpserver类中,

01538 class HTTPServer(object):
01539 “””An HTTP server.”””
01540
01541 _bind_addr = “127.0.0.1”

Definition at line 1682 of file __init__.py.

01682
01683     def start(self):
01684         """Run the server forever."""
01685         # We don't have to trap KeyboardInterrupt or SystemExit here,
01686         # because cherrpy.server already does so, calling self.stop() for us.
01687         # If you're using this server with another framework, you should
01688         # trap those exceptions in whatever code block calls start().
01689         self._interrupt = None
01690
01691         if self.software is None:
01692             self.software = "%s Server" % self.version
01693
01694         # SSL backward compatibility
01695         if (self.ssl_adapter is None and
01696             getattr(self, 'ssl_certificate', None) and
01697             getattr(self, 'ssl_private_key', None)):
01698             warnings.warn(
01699                     "SSL attributes are deprecated in CherryPy 3.2, and will "
01700                     "be removed in CherryPy 3.3. Use an ssl_adapter attribute "
01701                     "instead.",
01702                     DeprecationWarning
01703                 )
01704             try:
01705                 from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
01706             except ImportError:
01707                 pass
01708             else:
01709                 self.ssl_adapter = pyOpenSSLAdapter(
01710                     self.ssl_certificate, self.ssl_private_key,
01711                     getattr(self, 'ssl_certificate_chain', None))
01712
01713         # Select the appropriate socket
01714         if isinstance(self.bind_addr, basestring):
01715             # AF_UNIX socket
01716
01717             # So we can reuse the socket...
01718             try: os.unlink(self.bind_addr)
01719             except: pass
01720
01721             # So everyone can access the socket...
01722             try: os.chmod(self.bind_addr, 0777)
01723             except: pass
01724
01725             info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)]
01726         else:
01727             # AF_INET or AF_INET6 socket
01728             # Get the correct address family for our host (allows IPv6 addresses)
01729             host, port = self.bind_addr
01730             try:
01731                 info = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
01732                                           socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
01733             except socket.gaierror:
01734                 if ':' in self.bind_addr[0]:
01735                     info = [(socket.AF_INET6, socket.SOCK_STREAM,
01736                              0, "", self.bind_addr + (0, 0))]
01737                 else:
01738                     info = [(socket.AF_INET, socket.SOCK_STREAM,
01739                              0, "", self.bind_addr)]
01740
01741         self.socket = None
01742         msg = "No socket could be created"
01743         for res in info:
01744             af, socktype, proto, canonname, sa = res
01745             try:
01746                 self.bind(af, socktype, proto)
01747             except socket.error:
01748                 if self.socket:
01749                     self.socket.close()
01750                 self.socket = None
01751                 continue
01752             break
01753         if not self.socket:
01754             raise socket.error(msg)
01755
01756         # Timeout so KeyboardInterrupt can be caught on Win32
01757         self.socket.settimeout(1)
01758         self.socket.listen(self.request_queue_size)
01759
01760         # Create worker threads
01761         self.requests.start()
01762
01763         self.ready = True
01764         self._start_time = time.time()
01765         while self.ready:
01766             self.tick()
01767             if self.interrupt:
01768                 while self.interrupt is True:
01769                     # Wait for self.stop() to complete. See _set_interrupt.
01770                     time.sleep(0.1)
01771                 if self.interrupt:
01772                     raise self.interrupt

web.py解析

我想最好的python web编程入门,就是从web.py开始。

如果是想建立一个简单的网站,用web.py搭建。如果想深入学习python web编程,看web.py的源代码。

我们先看一下web.py的hello world:

import web

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

class hello:
    def GET(self):
        return 'Hello, world!'

if __name__ == "__main__":
    app.run()

这样第一看的代码是application的:
https://github.com/webpy/webpy/blob/master/web/application.py
class application:
    “””
Application to delegate requests based on path.
>>> urls = (“/hello”, “hello”)
>>> app = application(urls, globals())
>>> class hello:
… def GET(self): return “hello”
>>>
>>> app.request(“/hello”).data
‘hello’
“””
    def __init__(self, mapping=(), fvars={}, autoreload=None):
urls = ("/.*", "hello") 对应mapping
fvars 对应globals() .globals()返回当前的全局变量
 run对应的代码是:
  def run(self, *middleware):
        “””
Starts handling requests. If called in a CGI or FastCGI context, it will follow
that protocol. If called from the command line, it will start an HTTP
server on the port named in the first command line argument, or, if there
is no argument, on port 8080.
`middleware` is a list of WSGI middleware which is applied to the resulting WSGI
function.
“””
        return wsgi.runwsgi(self.wsgifunc(*middleware))
于是看:
def runwsgi(func):
    “””
Runs a WSGI-compatible `func` using FCGI, SCGI, or a simple web server,
as appropriate based on context and `sys.argv`.
“””
    server_addr = validip(listget(sys.argv, 1, ”))
    if os.environ.has_key(‘PORT’): # e.g. Heroku
        server_addr = (‘0.0.0.0′, intget(os.environ[‘PORT’]))
    return httpserver.runsimple(func, server_addr)
然后看:
def runsimple(func, server_address=(“0.0.0.0″, 8080)):
    “””
Runs [CherryPy][cp] WSGI server hosting WSGI app `func`.
The directory `static/` is hosted statically.
[cp]: http://www.cherrypy.org
“””
    global server
    func = StaticMiddleware(func)
    func = LogMiddleware(func)
    server = WSGIServer(server_address, func)
    if server.ssl_adapter:
        print “https://%s:%d/” % server_address
    else:
        print “http://%s:%d/” % server_address
    try:
        server.start()
    except (KeyboardInterrupt, SystemExit):
        server.stop()
        server = None
def WSGIServer(server_address, wsgi_app):
    “””Creates CherryPy WSGI server listening at `server_address` to serve `wsgi_app`.
This function can be overwritten to customize the webserver or use a different webserver.
“””
    import wsgiserver
webpy分析博文。

python 函数修饰符@(函数装饰器)以及staticmethod classmethod

大约明白了一点python里的@函数修饰符,有待继续深入学习/理解。
deco.py
#!/usr/bin/env python
from time import ctime, sleep
”’
def counter(func):
    if not hasattr(func, ‘ncalls’):
        print ‘*** initializing ctr’
        func.ncalls = [0]
    def wrappedFunc():
        func.ncalls[0] += 1
        print ‘*** incrementing ctr to’, func.ncalls
        print ‘INSIDE: id(func) =’, id(func)
        return func()
    print ‘id(func) =’, id(func)
    print ‘id(wrappedfunc) =’, id(wrappedFunc)
    wrappedFunc.ncalls = func.ncalls
    return wrappedFunc
”’
def tsfunc(func):
    def wrappedFunc():
        print ‘[%s] %s() called’ % (
            ctime(), func.__name__)
        return func()
    return wrappedFunc
def dcfunc(func):
    def printtime():
        print ‘dcfnc’,func
        return func()
    return printtime
@staticmethod
def testa():
    print testa
@classmethod
def testclass():
    print testclass
@tsfunc
@dcfunc
def foo():
    print (‘foo’,testa,testclass)
foo()
sleep(2)
for i in range(2):
    sleep(1)
    foo()
输出:

[Wed Mar 06 22:34:12 2013] printtime() called
dcfnc <function foo at 0x012292F0>
(‘foo’, <staticmethod object at 0x011F5ED0>, <classmethod object at 0x0122B110>)
[Wed Mar 06 22:34:15 2013] printtime() called
dcfnc <function foo at 0x012292F0>
(‘foo’, <staticmethod object at 0x011F5ED0>, <classmethod object at 0x0122B110>)
[Wed Mar 06 22:34:16 2013] printtime() called
dcfnc <function foo at 0x012292F0>
(‘foo’, <staticmethod object at 0x011F5ED0>, <classmethod object at 0x0122B110>)