python 游戏框架 热更_Python 函数热更 (开发时)

Python 函数热更 (开发时)

Python 函数热更(运行时更新)

标签(空格分隔): python

特性

实现函数运行时修改(开发环境!!!, 非线上热更!!!)

支持协程函数(tornado)

用法from/path/to/realtimefuncimportrealtimefunc

@coroutine

@realtimefunc

deftest():

# function body

故事

说到热更, 很容易就会联想到线上产品的热更. 有前端, 也有后台. 不过在这里提及到的是 python 后台开发时候的热更.

开发也需要热更 ??

开发也有人权的啊, 什么! 没有? 那就自己折腾个.

后端服务的启动一般需要做相当多的准备工作, 导致启动的速度比较慢. 开发时用的服务器一般比不上线上的, 启动速度就更引入注目了.

当你作为一个小白刚接触到一个 python 后端项目, 需要在上面做开发时, 你可能会遇到两个情况.

去理解一个功能, 数据存储的结构在理解占很大一部分, 对 python 这种动态数据结构, 通过代码, 很难清晰看到一个功能 (相关 dict,list, set 等) 定义的数据结构, 或者一些全局变量的具体结构以及内容. 一些固定的也许可以直接通过 db 查看数据结构, 但一些内存的中的数据, 就难以顾及了.

实现一个功能写了一大段代码, 这大段代码中隐藏 bug 团伙, python 是运行时检测, 也就是代码运行到具体语句才会报错, 这样报错之后的 bug 君依然得以隐藏, 如果服务启动需要 5 分钟, bug 团伙规模达到 6 个以上, 小半个小时就没了. 而这些 bug 可能只是简单 key error, 真是想想都要崩溃.

备注:

很多 web 框架有自启动, 是通过检测项目文件的 mtime , 然后替换掉当前的服务进程, 比如 tornado 就是用一个定时器定时检测项目文件, 实现 autostart.

这样很自然的就会想到, 如果可以随时改动开发的代码, 而不需要重启整个服务, 岂不是很爽.

实现目标:

实现一个装饰器, 被装饰的函数任意修改, 无需重启服务, 新请求立即生效.

实现思路:

在被装饰函数调用时, 利用 inspect.getsource 从 .py 文件获取该函数具体代码, 通过 exec 重新定义和命名该函数, 使得与函数代码的修改能在下次调用中生效. 最新代码地址 https://github.com/Graywd/realtimefunc# -*- coding: iso-8859-1 -*-

importsys

importlinecache

importre

frominspectimportgetsource,getfile

# A decorator is used to update a function at runtime.

DecoratorName='realtimefunc'

suffix='_runtime'

PY3=sys.version_info>=(3,)

ifPY3:

basestring_type=str

else:

basestring_type=basestring# noqa

def_exec_in(code,glob,loc=None):

# type: (Any, Dict[str, Any], Optional[Mapping[str, Any]]) -> Any

ifisinstance(code,basestring_type):

# exec(string) inherits the caller's future imports; compile

# the string first to prevent that.

code=compile(code,'','exec',dont_inherit=True)

exec(code,glob,loc)

def_handle_real_time_func_code(func,split='\n'):

code=getsource(func)

i_indent=0

i_decorator=0

code_lines=code.split(split)

func_pat=re.compile(r'^\s*def\s+'+func.__name__)

fori,lineinenumerate(code_lines):

if"@"+DecoratorNameinline:

i_decorator=i

iffunc_pat.match(line):

i_indent=line.index("def")

code_lines[i]=code_lines[i].replace(func.func_name,func.func_name+suffix,1)

break

# rm realtimefunc decorator

code_lines.pop(i_decorator)

# code indentation

code_lines=[line[i_indent:]forlineincode_lines]

code=split.join(code_lines)

returncode

defrealtimefunc(func):

defwrapper(*args,**kwargs):

filename=getfile(func)

# inspect use linecache to do file cache, so do checkcache first

linecache.checkcache(filename)

code_str=_handle_real_time_func_code(func)

_exec_in(code_str,func.__globals__,func.__globals__)

# A return expected when is work, if not yield instead.

returnfunc.__globals__[func.__name__+suffix](*args,**kwargs)

returnwrapper

效果

实现开发运行时修改函数, 可以很方便的查看和修改被装饰函数相关的数据, 以及构造简单测试数据和进行简单的分支测试.

注意

对于协成函数, 比如如果使用低版本的 tornado (比如 4.1) 请将 return 改为 yield, 位置在代码中有注释

inspect 中有用到 linecache 做缓存, 在获取函数源码的时候需要检查缓存

本文适用小白, 大神绕道, 小白自娱!!!

来源: https://www.cnblogs.com/nowg/p/9517478.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值