Python實踐:模塊自動重載

1、概述

開發Web程序時,一般會採用本地服務器進行調試,但若是代碼有變更,就須要重啓服務器。開發過程當中修改代碼是常常的事,不斷地重啓服務器既麻煩又耗時。所以爲了不這種笨拙的行爲,在流行的Web框架中,都提供了 模塊自動重載 的功能:不用重啓服務器,自動從新加載有變更的模塊。python

自動 的方式有不少,具體跟Web框架的實現強相關。像web.py中就是經過每次處理請求時都嘗試重載來模擬自動,而flask中則是使用獨立線程來完成的。簡單起見,本文的測試代碼中採用while循環(獨立進程)來實現自動。git

2、思路

遍歷已經加載的全部模塊,查看每一個模塊的對應文件的最近修改時間,若是時間有變化,則從新加載該模塊。github

3、實現

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Reload modules if modified

usage:
    python reloader.py [test_module_name]
"""

import sys
import os

mtimes = {}

def do_reload(handler=None):
    """Reload modules if modified
    """
    for module in sys.modules.values():
        # get filename
        filename = getattr(module, '__file__', None)
        if not (filename and os.path.isfile(filename)):
            continue

        # handle python file extensions
        # for more details about this topic,
        # see http://stackoverflow.com/questions/8822335/what-does-python-file-extensions-pyc-pyd-pyo-stand-for
        if filename[-4:] in ('.pyc', '.pyo', '.pyd'):
            filename = filename[:-1] # get the '.py' file

        # get the time of most recent content modification
        try:
            mtime = os.stat(filename).st_mtime
        except OSError:
            continue

        # reload `module` if it's modified
        old_time = mtimes.get(module)
        if old_time is None: # the first time in this function, just record mtime
            mtimes[module] = mtime
        elif old_time < mtime: # `module` is modified
            try:
                reload(module)
                mtimes[module] = mtime

                if handler: # call handler() if necessary
                    handler(module)

            except ImportError:
                pass

if __name__ == '__main__':
    if len(sys.argv) != 2:
        sys.stderr.write(__doc__)
        sys.exit(1)

    test_module_name = sys.argv[1]
    import importlib
    try:
        importlib.import_module(test_module_name)
    except ImportError, e:
        print(str(e))
        sys.exit(1)

    import time
    def handler(module):
        print(dir(module))

    print('start reloading module `%s` automatically...' % test_module_name)
    while True:
        try:
            do_reload(handler)
            time.sleep(2)
        except KeyboardInterrupt:
            break

4、測試

一、開啓自動重載(終端1)

$ touch testmod.py
$ python reloader.py testmod
start reloading module `testmod` automatically...

二、修改模塊(終端2)

$ vi testmod.py
...

三、查看實時輸出(終端1)

一旦對testmod.py有修改保存,終端1中會當即打印出模塊testmod的當前全部屬性。固然,也能夠修改handler來實現其餘的處理方式。web

5、參考源碼

(1)web.py的Reloaderflask

(2)werkzeug的_reloader_stat_loop服務器

相關文章
相關標籤/搜索