本文,我们学习一个叫birdseye的库,看看它是怎么实现Python代码debug可视化的。
先简单看看它的效果。
我用递归,写了一段生成斐波那契数列的函数,然后我用birdseye中的eye对函数进行装饰
from birdseye.server import main
from birdseye import eye
@eye
def fibonacci(n):
if n <= 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci(10)
main()
运行后,birdseye会启动一个web服务,通过这个web,我们可以很直观地调试与观察fibonacci函数中的各种数值。
效果如下:
这里,就不多讨论,怎么用它了,你可以直接看项目的github:https://github.com/alexmojaki/birdseye
本文主要要学习一下,人家是怎么做到这种效果的。
birdseye原理
还是老话,阅读任何一个项目的源码,都要有一个目的,因为代码里全是细节,如果没有目的,容易在细节里迷失。
我们阅读birdseye项目源码的目的主要就是:可视化debug是怎么实现的?
基于一开始的例子,我们很自然的,可以从eye装饰器入手,代码如下:
# birdseye/__init__.py
class _SimpleProxy(object):
def __init__(self, val):
# 设置了新的属性
object.__setattr__(self, '_SimpleProxy__val', val)
def __call__(self, *args, **kwargs):
return self.__val()(*args, **kwargs)
def __getattr__(self, item):
return getattr(self.__val(), item)
def __setattr__(self, key, value):
setattr(self.__val(), key, value)
eye = _SimpleProxy(lambda: import_module('birdseye.bird').eye)
eye其实是类装饰器,通过Python的动态import机制(import_module)将birdseye.bird中的eye引入。
在一开始,我不太理解,为啥要特意定义_SimpleProxy类将birdseye.bird.eye包裹多一层,其实就是通过_SimpleProxy类将其变为装饰器,birdseye.bird.eye则是具体的逻辑。
当项目运行时,eye装饰器会让_SimpleProxy类的__call__函数被调用,从而执行birdseye的业务逻辑。
为了避免迷茫,这里先概述一下birdseye的原理,经过学习,birdseye做到可视化debug主要通过下面几步:
1.通过eye装饰器获得被装饰函数的AST(抽象语法树)
2.修改AST,实现对函数中的每个语句(stmt&