最近拿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)
未完待續......