web.py源码(持续更新)

文件结构:
utils.py中定义的是些 General Utilities,通用工具集和数据结构

1.对序列进行分组的函数(生成器的很好使用,值得借鉴)group

 1 def group(seq, size): 
 2     
 3     def take(seq, n):
 4         for i in xrange(n):
 5             yield seq.next()
 6 
 7     if not hasattr(seq, 'next'):  
 8         seq = iter(seq)
 9     
10     while True: 
11         
12         inger=take(seq, size)
13         x = list(inger)
14         if x:
15             yield x
16         else:
17             break
/*重点在take生成器,每次调用后seq会停留在的上次迭代n次seq结束的seq[n]处,因为seq被转换成了迭代器,next会一直有效直到所有元素迭代完为止,
把生成器转换成列表,实际上也是调用next,直到抛出StopIteration异常,被list捕获*/

 1 def take(seq, n):
 2     for i in xrange(n):
 3         yield seq.next()
 4         
 5 #while True:
 6 #    inger=take(seq,2)
 7 #    import time
 8 #    time.sleep(1)
 9 #    print list(inger) #迭代到最后一个异常被捕获
10 
11 res=take(seq,2)
12 #print list(res)
13 print res.next()
14 print res.next()
15 res=take(seq,2)
16 #print list(res)
17 print res.next()
18 print res.next()
19 res=take(seq,2)
20 #print list(res)
21 print res.next()
22 print res.next() #StopIteration,被list捕获


#web.py-0.111中的实现不能,分出最后一个元素
 1 def group(seq, size): 
 2     """Breaks 'seq' into a generator of lists with length 'size'."""
 3     if not hasattr(seq, 'next'):  seq = iter(seq)
 4     
 5     while True: yield [seq.next() for i in xrange(size)]
 6 
 7 seq=iter([1,2,3,4,5])
 8 
 9 #r=group(seq,2)
10 #print r.next()
11 #print r.next()
12 #print r.next() #抛出异常,因此没有生成[5]

 

2.#缓存函数每个线程调用的返回结果。memoize

 1 class memoize:(web.py-0.111定义的版本)
 2     def __init__(self, func): 
 3         self.func = func; 
 4         self.cache = {}
 5     def __call__(self, *a, **k):
 6         key = (a, tuple(k.items()))
 7         if key not in self.cache: 
 8             print "no cahe"
 9             self.cache[key] = self.func(*a, **k)
10         print "cache",self.cache[key]
11         return self.cache[key]
12 
13 
14 
15 def test(a):
16     return a
17 
18 
19 me_test=memoize(test)
20 
21 me_test("aa")
22 
23 t=threading.Thread(target=me_test,args=('aa',))
24 
25 t.start()
26 t.join()
class Memoize:(web.py 0.37)
    """
    'Memoizes' a function, caching its return values for each input.
    If `expires` is specified, values are recalculated after `expires` seconds.
    If `background` is specified, values are recalculated in a separate thread.
    
        >>> calls = 0
        >>> def howmanytimeshaveibeencalled():
        ...     global calls
        ...     calls += 1
        ...     return calls
        >>> fastcalls = memoize(howmanytimeshaveibeencalled)
        >>> howmanytimeshaveibeencalled()
        1
        >>> howmanytimeshaveibeencalled()
        2
        >>> fastcalls()
        3
        >>> fastcalls()
        3
        >>> import time
        >>> fastcalls = memoize(howmanytimeshaveibeencalled, .1, background=False)
        >>> fastcalls()
        4
        >>> fastcalls()
        4
        >>> time.sleep(.2)
        >>> fastcalls()
        5
        >>> def slowfunc():
        ...     time.sleep(.1)
        ...     return howmanytimeshaveibeencalled()
        >>> fastcalls = memoize(slowfunc, .2, background=True)
        >>> fastcalls()
        6
        >>> timelimit(.05)(fastcalls)()
        6
        >>> time.sleep(.2)
        >>> timelimit(.05)(fastcalls)()
        6
        >>> timelimit(.05)(fastcalls)()
        6
        >>> time.sleep(.2)
        >>> timelimit(.05)(fastcalls)()
        7
        >>> fastcalls = memoize(slowfunc, None, background=True)
        >>> threading.Thread(target=fastcalls).start()
        >>> time.sleep(.01)
        >>> fastcalls()
        9
    """
    def __init__(self, func, expires=None, background=True): 
        self.func = func
        self.cache = {}
        self.expires = expires
        self.background = background
        self.running = {}
    
    def __call__(self, *args, **keywords):
        key = (args, tuple(keywords.items()))
        if not self.running.get(key):
            self.running[key] = threading.Lock()
        def update(block=False):
            if self.running[key].acquire(block):
                try:
                    self.cache[key] = (self.func(*args, **keywords), time.time())
                finally:
                    self.running[key].release()
        
        if key not in self.cache: 
            update(block=True)
        elif self.expires and (time.time() - self.cache[key][1]) > self.expires:
            if self.background:
                threading.Thread(target=update).start()
            else:
                update()
        return self.cache[key][0]

memoize = Memoize

re_compile = memoize(re.compile) #@@ threadsafe?
re_compile.__doc__ = """
A memoized version of re.compile.
"""
View Code

 

 

3.重定向输出到一个对象中(在类中定义一个write方法,用于重定向)

 1         
 2 import sys
 3 
 4 
 5 
 6 class A(object):
 7     text=''
 8     
 9 class _outputter(object):
10     def write(self, x): 
11         A.text+=x
12         
13 _oldstdout=sys.stdout
14 sys.stdout=_outputter()
15 print "xxxxxxxx"
16 sys.stdout=_oldstdout
17 print "ctx:",A.text

 4.捕获异常,格式化信息输出的函数(可以借用)(web.py-0111)

 1 def djangoerror():
 2     def _get_lines_from_file(filename, lineno, context_lines):
 3         """
 4         Returns context_lines before and after lineno from file.
 5         Returns (pre_context_lineno, pre_context, context_line, post_context).
 6         """
 7         try:
 8             source = open(filename).readlines()
 9             lower_bound = max(0, lineno - context_lines)
10             upper_bound = lineno + context_lines
11 
12             #pre_context = [line.strip('\n') for line in source[lower_bound:lineno]]
         pre_context = [line.strip('\n') for line in source[lower_bound-1:lineno-1]]
13 #context_line = source[lineno].strip('\n')
         context_line = source[lineno-1].strip('\n')#因为readlines是从索引0开始的
14 #post_context = [line.strip('\n') for line in source[lineno+1:upper_bound]]
         post_context = [line.strip('\n') for line in source[lineno:upper_bound]]
15 16 return lower_bound, pre_context, context_line, post_context 17 except (OSError, IOError): 18 return None, [], None, [] 19 20 exception_type, exception_value, tb = sys.exc_info() 21 frames = [] 22 while tb is not None: 23 filename = tb.tb_frame.f_code.co_filename 24 function = tb.tb_frame.f_code.co_name 25 #lineno = tb.tb_lineno - 1 #异常信息所在行号显示不对
      lineno = tb.tb_lineno 26 pre_context_lineno, pre_context, context_line, post_context = _get_lines_from_file(filename, lineno, 7) 27 frames.append({ 28 'tb': tb, 29 'filename': filename, 30 'function': function, 31 'lineno': lineno, 32 'vars': tb.tb_frame.f_locals.items(), 33 'id': id(tb), 34 'pre_context': pre_context, 35 'context_line': context_line, 36 'post_context': post_context, 37 'pre_context_lineno': pre_context_lineno, 38 }) 39 tb = tb.tb_next

    #frames 保存跟踪异常回溯的每层 信息
40 lastframe = frames[-1] 41 urljoin = urlparse.urljoin 42 input_ = input() 43 cookies_ = cookies() 44 context_ = context 45 prettify = pprint.pformat 46 47 #格式化的异常信息,方便在模板展示 48 frames 以及下面的局部变量可以 用于HTML模板系统展示

用于异常展示的HTML模板(django框架里面的):基于Cheetah模板系统(Cheetah是一个用Python写的模板系统与代码生成工具)

 1 def djangoerror():
 2     def _get_lines_from_file(filename, lineno, context_lines):
 3         """
 4         Returns context_lines before and after lineno from file.
 5         Returns (pre_context_lineno, pre_context, context_line, post_context).
 6         """
 7         try:
 8             source = open(filename).readlines()
 9             lower_bound = max(0, lineno - context_lines)
10             upper_bound = lineno + context_lines
11 
12             pre_context = [line.strip('\n') for line in source[lower_bound:lineno]]
13             context_line = source[lineno-1].strip('\n')#因为readlines是从索引0开始的
14             post_context = [line.strip('\n') for line in source[lineno:upper_bound]]
15 
16             return lower_bound, pre_context, context_line, post_context
17         except (OSError, IOError):
18             return None, [], None, []    
19     
20     exception_type, exception_value, tb = sys.exc_info()
21     frames = []
22     while tb is not None:
23         filename = tb.tb_frame.f_code.co_filename
24         function = tb.tb_frame.f_code.co_name
25         lineno = tb.tb_lineno #- 1#不减一显示的是报异常那句后面的语句,在_get_lines_from_file,处理readlines减1,显示正常
26         pre_context_lineno, pre_context, context_line, post_context = _get_lines_from_file(filename, lineno, 7)
27         frames.append({
28             'tb': tb,
29             'filename': filename,
30             'function': function,
31             'lineno': lineno,
32             'vars': tb.tb_frame.f_locals.items(),
33             'id': id(tb),
34             'pre_context': pre_context,
35             'context_line': context_line,
36             'post_context': post_context,
37             'pre_context_lineno': pre_context_lineno,
38         })
39         tb = tb.tb_next
40     lastframe = frames[-1]
41     urljoin = urlparse.urljoin
42     input_ = input()
43     cookies_ = cookies()
44     context_ = context
45     prettify = pprint.pformat
46     
47     #格式化的异常信息,方便在模板展示
48     return render(DJANGO_500_PAGE, asTemplate=True, isString=True)
View Code

--------------------------------
web.py中定义几种数据结构:
1. Storage类,在utils文件中定义, 类字典对象,从内建对象dict派生,通过实现特殊方法:__getattr__,__setattr__,__delattr__,
以至于像设置、获取、删除对象的属性和值一样设置、获取、删除字典的键和值。

class Storage(dict):
    def __getattr__(self, key): 
        try:
            return self[key]
        except KeyError, k:
            raise AttributeError, k
    
    def __setattr__(self, key, value): 
        self[key] = value
    
    def __delattr__(self, key):
        try:
            del self[key]
        except KeyError, k:
            raise AttributeError, k
    
    def __repr__(self):     
        return '<Storage ' + dict.__repr__(self) + '>'

web.config 初始化的是一个storge对象

2.ThreadedDict类,在utils文件中定义,线程字典,线程安全的,该实例化对象存在于主线程中,但是其属性值 在每一个线程中是独立的

 1     """
 2     Thread local storage.
 3     
 4         >>> d = ThreadedDict()
 5         >>> d.x = 1
 6         >>> d.x
 7         1
 8         >>> import threading
 9         >>> def f(): d.x = 2
10         ...
11         >>> t = threading.Thread(target=f)
12         >>> t.start()
13         >>> t.join()
14         >>> d.x
15         1
16     """
当前版本的实现:(
依赖于threading模块的local (在python23.py 有个专门对python2.3实现的threadlocal)

  1 import threading
  2 from threading import local as threadlocal
  3 
  4 class threadlocal(object):
  5     """Implementation of threading.local for python2.3.
  6     """
  7     def __getattribute__(self, name):
  8         if name == "__dict__":
  9             return threadlocal._getd(self)
 10         else:
 11             try:
 12                 return object.__getattribute__(self, name)
 13             except AttributeError:
 14                 try:
 15                     return self.__dict__[name]
 16                 except KeyError:
 17                     raise AttributeError, name
 18             
 19     def __setattr__(self, name, value):
 20         self.__dict__[name] = value
 21         
 22     def __delattr__(self, name):
 23         try:
 24             del self.__dict__[name]
 25         except KeyError:
 26             raise AttributeError, name
 27     
 28     def _getd(self):
 29         t = threading.currentThread()
 30         if not hasattr(t, '_d'):
 31             # using __dict__ of thread as thread local storage
 32             t._d = {}
 33         
 34         _id = id(self)
 35         # there could be multiple instances of threadlocal.
 36         # use id(self) as key
 37         if _id not in t._d:
 38             t._d[_id] = {}
 39         return t._d[_id]
 40     
 41 class ThreadedDict(threadlocal):
 42 
 43     _instances = set()
 44     
 45     def __init__(self):
 46         ThreadedDict._instances.add(self)
 47         
 48     def __del__(self):
 49         ThreadedDict._instances.remove(self)
 50         
 51     def __hash__(self):
 52         return id(self)
 53     
 54     def clear_all():
 55         """Clears all ThreadedDict instances.
 56         """
 57         for t in list(ThreadedDict._instances):
 58             t.clear()
 59     clear_all = staticmethod(clear_all)
 60     
 61     # Define all these methods to more or less fully emulate dict -- attribute access
 62     # is built into threading.local.
 63 
 64     def __getitem__(self, key):
 65         return self.__dict__[key]
 66 
 67     def __setitem__(self, key, value):
 68         self.__dict__[key] = value
 69 
 70     def __delitem__(self, key):
 71         del self.__dict__[key]
 72 
 73     def __contains__(self, key):
 74         return key in self.__dict__
 75 
 76     has_key = __contains__
 77         
 78     def clear(self):
 79         self.__dict__.clear()
 80 
 81     def copy(self):
 82         return self.__dict__.copy()
 83 
 84     def get(self, key, default=None):
 85         return self.__dict__.get(key, default)
 86 
 87     def items(self):
 88         return self.__dict__.items()
 89 
 90     def iteritems(self):
 91         return self.__dict__.iteritems()
 92 
 93     def keys(self):
 94         return self.__dict__.keys()
 95 
 96     def iterkeys(self):
 97         return self.__dict__.iterkeys()
 98 
 99     iter = iterkeys
100 
101     def values(self):
102         return self.__dict__.values()
103 
104     def itervalues(self):
105         return self.__dict__.itervalues()
106 
107     def pop(self, key, *args):
108         return self.__dict__.pop(key, *args)
109 
110     def popitem(self):
111         return self.__dict__.popitem()
112 
113     def setdefault(self, key, default=None):
114         return self.__dict__.setdefault(key, default)
115 
116     def update(self, *args, **kwargs):
117         self.__dict__.update(*args, **kwargs)
118 
119     def __repr__(self):
120         return '<ThreadedDict %r>' % self.__dict__
121 
122     __str__ = __repr__
该类继承自 threading.local 类,然后定制成类字典对象

web.py 0.111中的实现。依赖于threading中的currentThread:(每个线程都必须用线程id作为键更新全局_context字典对象,以便线程根据自己的线程id访问/设置自己的属性)

class threadeddict:
    def __init__(self, d): 
        self.__dict__['_threadeddict__d'] = d #相当于设置一个__d私有属相
        
    def __getattr__(self, a): 
        return getattr(self.__d[currentThread()], a)
    
    def __getitem__(self, i): 
        return self.__d[currentThread()][i]
    
    def __setattr__(self, a, v): 
        return setattr(self.__d[currentThread()], a, v)
    
    def __setitem__(self, i, v): 
        self.__d[currentThread()][i] = v

###使用示例####
   _context = {currentThread():Storage()}
    mydata=threadeddict(_context)
    mydata.number=345
    print mydata.number
    
    def f():
        _context[currentThread()]= Storage()#添加键位当前线程id的项
        mydata.number=22
        print mydata.number

    t=threading.Thread(target=f)
    t.start()
    t.join()
    print mydata.number
-----------
>345
>22
>345

 

-------------------------------------
1. application类

钩子函数:
loadhook(func) 在处理请求之前 func()
unloadhook(func) 在处理请求之后 func()

app.add_processor(processor) processor的参数为handler:请求处理函数

web.config.debug=False 请求处理不会自动重新加载 app所在模块的对象,web.py自带的服务器默认值为True
在 wsgi.py 中web.config.setdefault('debug', _is_dev_mode())设置debug的默认值,_is_dev_mode判断是否是开发环境

 

wsgifunc 方法,返回一个兼容WSGI的application函数 ,接受一系列中间件middleware参数

该方法中定义的函数

peep(iterator)  '''Peeps into an iterator by doing an iteration and returns an equivalent iterator.'''

is_generator(x) 判断对象是否是一个生成器

wsgi

 

 

_cleanup 方法 清除所有ThreadedDict的是实例对象(每实例化一个线程字典对象都会被保存)

load 方法,用env字典变量初始化web.ctx各项属性值. 在wsgiffunc方法返回的wsgi函数中调用

 

附------------

os.stat(mod.__file__).st_mtime os.stat()获取文件的相关属性

itertools.chain 分别迭代多个序列或迭代器对象,然后连接在一起转换成一个迭代器

sys._getframe(1).f_locals  

Return a frame object from the call stack. If optional integer depth is
given, return the frame object that many calls below the top of the stack.
If that is deeper than the call stack, ValueError is raised. The default
for depth is zero, returning the frame at the top of the call stack.

 

 

posted @ 2014-12-17 22:04  Aveen  阅读(1090)  评论(0)    收藏  举报
Top