动态加载python源代码

时间:2010-12-22 21:56:50

标签: python dynamic flask

我正在玩Flask,我无法弄清楚调试机制是如何工作的。更准确地说,当我使用我的应用程序保存python文件时,我不需要重新启动服务器,它会在我发出请求时自动加载。所以我的问题是正在运行的程序如何知道它已被更改并响应这些更改?

2 个答案:

答案 0 :(得分:7)

Flask正在使用Werkzug的基础run_with_reloader函数(在serving.py中找到)...它本身使用之前在同一文件中创建的restart_with_reloaderreloader_loop函数。

run_with_reloader产生另一个python进程(再次使用传递给第一个的所有相同参数运行Werkzug)并且这个新进程使用thread模块生成一个新的线程或运行的子进程你的服务器功能。然后它运行reloader_loop并等待。

reloader_loop只循环遍历已导入的所有模块并获取其上次修改日期。然后按指定的时间间隔(默认为1秒),它会再次检查所有文件以查看它们是否已被修改。如果有,则当前运行的( slave )Werkzug进程以退出代码3退出(终止)。一旦退出,它启动的线程或子进程(实际上正在进行的工作)终止同样。 进程检查退出代码是否为3.如果是,则生成新的 slave 子进程,就像之前一样。否则,它将以相同的退出代码退出。

以下是供参考的代码:

def reloader_loop(extra_files=None, interval=1):
    """When this function is run from the main thread, it will force other
    threads to exit when any modules currently loaded change.

    Copyright notice.  This function is based on the autoreload.py from
    the CherryPy trac which originated from WSGIKit which is now dead.

    :param extra_files: a list of additional files it should watch.
    """
    def iter_module_files():
        for module in sys.modules.values():
            filename = getattr(module, '__file__', None)
            if filename:
                old = None
                while not os.path.isfile(filename):
                    old = filename
                    filename = os.path.dirname(filename)
                    if filename == old:
                        break
                else:
                    if filename[-4:] in ('.pyc', '.pyo'):
                        filename = filename[:-1]
                    yield filename

    mtimes = {}
    while 1:
        for filename in chain(iter_module_files(), extra_files or ()):
            try:
                mtime = os.stat(filename).st_mtime
            except OSError:
                continue

            old_time = mtimes.get(filename)
            if old_time is None:
                mtimes[filename] = mtime
                continue
            elif mtime > old_time:
                _log('info', ' * Detected change in %r, reloading' % filename)
                sys.exit(3)
        time.sleep(interval)


def restart_with_reloader():
    """Spawn a new Python interpreter with the same arguments as this one,
    but running the reloader thread.
    """
    while 1:
        _log('info', ' * Restarting with reloader...')
        args = [sys.executable] + sys.argv
        new_environ = os.environ.copy()
        new_environ['WERKZEUG_RUN_MAIN'] = 'true'

        # a weird bug on windows. sometimes unicode strings end up in the
        # environment and subprocess.call does not like this, encode them
        # to latin1 and continue.
        if os.name == 'nt':
            for key, value in new_environ.iteritems():
                if isinstance(value, unicode):
                    new_environ[key] = value.encode('iso-8859-1')

        exit_code = subprocess.call(args, env=new_environ)
        if exit_code != 3:
            return exit_code


def run_with_reloader(main_func, extra_files=None, interval=1):
    """Run the given function in an independent python interpreter."""
    if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
        thread.start_new_thread(main_func, ())
        try:
            reloader_loop(extra_files, interval)
        except KeyboardInterrupt:
            return
    try:
        sys.exit(restart_with_reloader())
    except KeyboardInterrupt:
        pass

答案 1 :(得分:0)

内置reload()功能可以为您完成此操作。很可能这个功能落后于Flask重新加载代码所做的事情(注意到它在某些方面已经在磁盘上发生了变化)。

问题How do I unload (reload) a Python module?提供了更多相关信息。

相关问题