说明

我们通常会在系统功能上线后需要修改某一部分的内容,但是我们又不希望重新启动整个系统。以下基于这个应用进行介绍。

方法:通过imp的reload函数进行「模块」的重载

内容

首先要区别python里面模块和包的概念,具体的可以参考这篇文章

在Python中,一个.py文件就称之为一个模块(Module)。

Python又引入了按目录来组织模块的方法,称为包(Package)。包可以理解为一个文件夹,里面有若干.py文件,并且有一个__init__.py文件

注意:我们引用的函数是存在模块里的,要对对应的模块重载(而不是包)

例子

包的重载实验
├── entry_flask.py
└── task_pack
    ├── __init__.py
    └── task1.py

entry_flask.py中构建了一个简单的服务(不使用debug模式),其中whoami和index只是为了维持一个规范写的,不用去看。主要有两个函数与本例有关:reload_moduletasks

from flask import Flask, request, jsonify
from imp import reload
# import aa as tpack
import task_pack as tpack
# 初始化app
app = Flask(__name__)


@app.route('/whoami/', methods=['GET', 'POST'])
def whoami():
    pass 


@app.route('/', methods=['GET', 'POST'])
def index():
    return 'Hello , I am Server'

# 好像只能按模块reload
@app.route('/reload_module/<task_name>',methods=['GET', 'POST'])
def reload_module(task_name):
    reload(getattr(tpack, task_name))
    return 'ok'


# 暂时假设无参(如果有参需要考虑序列化问题,一般python的数据需要pkl序列化)
@app.route('/tasks/<task_name>', methods=['GET', 'POST'])
def tasks(task_name):
    print(task_name)
    # 是否存在任务
    is_task = hasattr(tpack, task_name)
    print(is_task)
    if is_task:
        task_module = getattr(tpack, task_name)
        print(task_module)
        task_func = getattr(task_module, task_name)
        return task_func()
         
    else:
        return 'no taskname'

if __name__ == '__main__':
    # app.run(debug=True)
    app.run()

task1.py内容

def task1():
    the_str = 'hello , i am task1 , modified 4 '
    print(the_str)
    return the_str

__init__.py内容

from . import task1

task_pack的作用是把许多task整合到一起,一个task一个文件(模块)。

时刻1:调用task1,内容如下

python 配置文件ini python 配置文件热加载_python 配置文件ini


时刻2:修改task1

def task1():
    the_str = 'hello , i am task1 , modified 5 '
    print(the_str)
    return the_str

结果没有变化:

python 配置文件ini python 配置文件热加载_python_02


时刻3:请求热加载模块

python 配置文件ini python 配置文件热加载_python_03


时刻4:再次请求,返回重新加载(更改)过的结果。

python 配置文件ini python 配置文件热加载_python 配置文件ini_04


另外,从增删改查(CRUD)的角度上,做如下修改:

# 好像只能按模块reload
@app.route('/reload_module/<task_name>',methods=['GET', 'POST'])
def reload_module(task_name):
    if not hasattr(tpack,task_name):
        reload(tpack)
    else:
        reload(getattr(tpack, task_name))
    return 'ok'


@app.route('/remove_task/<task_name>', methods=['GET', 'POST'])
def remove_task(task_name):
    if not hasattr(tpack, task_name):
        return 'no such task'
    else:
        delattr(tpack, task_name)
        return 'ok, remove' + task_name

reload_module的修改使得新增task时(当前内存里加载的包没有这个属性),会对整个包进行加载(Create);原来的则是对已有包的修改(Update)。
remove_task是一种软删除(soft DELETE)的方法,它使得当前运行的内存中去掉了某个task; 如果要彻底删除(hard DELETE)的化就在包里的__init__.py中去掉某个task的导入就可以了。

用途

  • 1 在celery的任务框架中,动态修改任务
  • 2 在启动服务的时候加载静态资源,通过热加载的方式改变静态资源