最近拿python的单文件开源web框架bottle源码看了一下,麻雀虽小五脏俱全,看bottle源码还是能学到很多python的实践用法。
这里会陆续写一些阅读中的收获。
1. makelist函数
def makelist(data):
'''包装对象成为list'''
if isinstance(data, (tuple, list, set, dict)): return list(data)
elif data: return [data] # 对除去上述以外的元素生成list
else: return []
疑问:当碰到自定义的可迭代对象的时候,会返回[<iterator>]。在作者自己的代码中没有碰到这样的情况,但是我们也可以来扩展一下。
def makelist_mod(data):
'''包装任意对象成为list'''
if getattr(data, '__iter__', False): return list(data)
elif data: return [data]
else: return []
2. DictProperty装饰器
class DictProperty(object):
'''映射修饰后的property到owner class中的某个类似字典的attribute
(后文也用property和attribute,而不用属性,以表示区别)'''
def __init__(self, attr, key=None, read_only=False):
self.attr, self.key, self.read_only = attr, key, read_only
# 以调用的方法使用装饰器,则被装饰的函数在__call__方法里作为参数传入
def __call__(self, func):
# 用update_wrapper的方法把func的__module__,__name__,__doc__赋给装饰后的attribute
functools.update_wrapper(self, func, updated=[])
self.getter, self.key = func, self.key or func.__name__
return self # 这个attribute是DictProperty的实例
def __get__(self, obj, cls): # 参数依次为被装饰后的实例,owner class的实例,owner class
if obj is None: return self
key, storage = self.key, getattr(obj, self.attr) # self.attr是owner class的一个attribute
if key not in storage: storage[key] = self.getter(obj)
return storage[key]
def __set__(self, obj, value):
if self.read_only: raise AttributeError("Read-Only property.")
getattr(obj, self.attr)[self.key] = value
def __delete__(self, obj):
if self.read_only: raise AttributeError("Read-Only property.")
del getattr(obj, self.attr)[self.key]
用法:
class sample(object):
def __init__(self):
self.config = {}
@DictProperty('config', 'sample.foo', read_only=True)
def foo(self):
return 'foo'
@DictProperty('config', 'sample.bar', read_only=True)
def bar(self):
return 'bar'
归纳:这个装饰器装饰后形成的property在修改后,会改变owner class中绑定的attribute。
3. CachedProperty装饰器
class CachedProperty(object):
'''每个实例只在第一次get的时候计算的property的值,之后存在instance的__dict__
中(当访问对象的property时,如果__dict__中有,则先返回__dict__中记录的值,如
果没有,则执行被访问property的__get__的方法。)'''
def __init__(self, func):
self.func = func
def __get__(self, obj, cls):
if obj is None: return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value
这个很简单,能看懂上面DictProperty,这个小case了
4. lazy_attribute装饰器
class lazy_attribute(object):
'''会在第一次调用的时候,把计算的结果设为owner class的attribute'''
def __init__(self, func):
functools.update_wrapper(self, func, updated=[])
self.getter = func
def __get__(self, obj, cls):
value = self.getter(cls)
setattr(cls, self.__name__, value)
return value
--------------------------------------------------------------------------------
5. reloader实现
#coding: utf-8 import os, sys, time, subprocess, thread # 当前文件路径 path = os.path.abspath(__file__) # 当前文件修改时间 mtime = os.stat(path).st_mtime # 主进程为控制器,不做功能处理 if not os.environ.get('is_child'): argv = [sys.executable] + sys.argv environ = os.environ.copy() # 给子进程标记,不做控制功能 environ['is_child'] = 'true' # 先开一个子进程,执行程序功能 p = subprocess.Popen(argv, env=environ) while True: if os.stat(path).st_mtime != mtime: mtime = os.stat(path).st_mtime p = subprocess.Popen(argv, env=environ) print 'reloaded' time.sleep(1) # 程序功能部分 def main(): print 'try to modifdy this part and save!' raw_input() # 模拟监听请求 # 新线程执行功能 thread.start_new_thread(main, ()) # 主线程监听结束 while True: if mtime < os.stat(path).st_mtime: sys.exit(0) time.sleep(1)
未完待续......