python函数调用键盘热键是哪个_Python 函数热更(开发时)

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

标签(空格分隔): python

特性

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

支持协程函数(tornado)

用法

from /path/to/realtimefunc import realtimefunc

@coroutine

@realtimefunc

def test():

# function body

故事

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

开发也需要热更 ??

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

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

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

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

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

备注:

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

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

实现目标:

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

实现思路:

在被装饰函数调用时, 利用 inspect.getsource 从 .py 文件获取该函数具体代码, 通过 exec 重新定义和命名该函数, 使得与函数代码的修改能在下次调用中生效。最新代码地址 realtimefunc

# -*- coding: iso-8859-1 -*-

import sys

import linecache

import re

from inspect import getsource, getfile

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

DecoratorName = 'realtimefunc'

suffix = '_runtime'

PY3 = sys.version_info >= (3,)

if PY3:

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

if isinstance(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__)

for i, line in enumerate(code_lines):

if "@"+DecoratorName in line:

i_decorator = i

if func_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:] for line in code_lines]

code = split.join(code_lines)

return code

def realtimefunc(func):

def wrapper(*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.

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

return wrapper

效果

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

注意

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值