介绍
最近看到了kennethreitz的介绍(谁说程序员不是潜力股?让这位世界前五名的天才程序员来颠覆你三观!),实在太励志了!然后看了一下github仓库,看到几个比较短的项目,觉得挺好玩的,就记录一下分析结果。
records这个项目一共才415行代码,核心代码才一两百行,主要基于sqlalchemy和tablib两个库,这么少的代码就实现了对数据库提供python化查找和分析。只需要输入sql语句就可以把结果包成对象返回,极大的方便了用户。其实我个人觉得还可以更简洁一点,在query接口中,只提供了table的名称,连sql都不用写。
分析sqlalchemy:python的ORM框架
tablib:kennethreitz的另一个项目,主要是把数据处理为XLS, CSV, JSON, YAML格式返回。
项目一共有三个核心的class,Database,RecordCollection,Record。我们就以这三个class讲开。
Record储存每条数据的详情;RecordCollection储存query的查找结果,也就是Record的集合;Database数据库的操作集合。
形象的来说:RecordCollection就是拉皮条的,手里有很多的Record,来源自Database,客户就是我们。。。。
Database
对数据库的连接和操作的封装,也就是sqlalchemy的操作。环境变量
records不仅可以传db_url,而且也提供环境变量DATABASE_URL。
2. 上下文管理协议
包含的方法__enter__()和__exit__(),__enter__()是在语句体执行之前运行的,__exit__()是在语句体结束后运行的。最常用的就是with()的用法。在records里面,__enter__()返回了整个对象,__exit__()主要是把db连接关掉。使用上下文之后,可以使连接能及时关掉。
# 上下文的例子
class Student(object):
def __enter__(self):
# 进入
print('coming')
return 'student'
def __exit__(self, exc_type, exc_val, exc_tb):
# 离开
print('byebye')
def func():
return Student()
with func() as a:
print(a)
# result
>>> python a.py
coming
student
byebye
3. __repr__()
重构了__repr__()方法,在里面加入了db是否连接。刚开始定义的open变量作用就只是用在这里显示。
4. query()
query()就是Database里面最核心的一个方法了,对数据库进行查找,把结果存储到Record对象中,并把Record集合存储到RecordCollection,并返回。
5. query_file()
读取文件中的sql语句,在最后也是使用query()方法。
6. transaction
在records里面也是有事务操作。
RecordCollection
正如注释所讲: A set of excellent Records from a query.生成器
在Database中的query()方法中,如果你传入了fetchall为True的话,就会把生成器全部执行完,这个时候pending就为False。
所以pending变量的作用就是用来了解生成器的值有没有全部取出来。
__next__()和__iter__()两个方法主要就是实现了整个生成器,利用生成器极大的节省了内存开销。在生成器中还加入了_all_rows这个变量,在每次迭代,都会把值存入里面,然后每次取值,都会从里面拿。相当于缓存了_all_rows里面。
2. 导出数据
RecordCollection和Record都有export,一个是导出整个表,一个是导出某一条。用的就是tablib,能导出各种格式。
Record多格式输出
可以用row.user_email, row['user_email'], row[3]
使用__getitem__()和__getattr__()进行配合,如果是row[3]的话,__getitem__()能直接抓取到,如果是str的话,__getattr__()抓取到然后传给__getitem__()解析。
包括提供的get()方法,其实也是__getitem__()解析的。
所有通过[]取数据都会走到__getitem__()方法。
2. 导出数据
Record也是使用的tablib导出数据,跟RecordCollection类似。
3. __slots__
如果有大量的计算和循环的话,可以使用__slots__,能节省很大的内存消耗。由于keys和values需要经常访问,用了__slots__可以减少访问速度。
命令行工具
利用docopt来创建命令行工具。docopt的具体用法可以参考另外一篇文章python库学习: 命令行参数解析库docopt。
总结
records这个库充分利用了python的特殊方法,如__getitem__(),__getattr__(),__slots__()等。并且在整个架构上面设计也是十分合理,非常适合阅读源码。