版权声明:此文章转载自infocool
原文链接:http://www.infocool.net/kb/Python/201607/161414.html
如需转载请联系听云College团队成员小尹 邮箱:yinhy#tingyun.com
1.1. 前言
在上一篇文章我们展示了使用装饰器来完成拆分后的编写SQL。好处是让代码变的更加的厉害,更容易的应变未来需求的变更了。但是,麻烦的是免不了需要添加新的装饰器。当然这对哪些较劲的来说肯定还说:之前的开发麻烦,代码有没减。这种效果当然也不是我想要的。
下面我们就来使用“动态装饰器”来实现,让我的代码更加的少。
1.2. 回顾和找相同
回顾之前装饰器的3个方法(join_order、join_order_good、join_coupon),细心的会发现它们里面的代码几乎是相同的,除了需要关联的字段和调用获取数据方法如下表:
装饰器方法 装饰器中需要调用的方法 拼凑时需要关联的字段
join_orderget_order_infouser_id join_order_goodget_order_good_infoorder_id join_couponget_coupon_infoorder_id
通过比较代码和分析。我们想我们能不能将 装饰器中需要调用的方法 和 拼凑时需要关联的字段 通过变量的方式带入装饰器,这样我们就可以使用一个装饰器来满足所有装饰器的功能呢?答案是肯定的。
1.3. 实现程序
我们通过实现一个动态装饰器方法(join_data)来完成我们的目标。这个装饰器有两个参数func_name、col_name:
func_name:需要动态执行的方法名。
col_name:两个结果集关联的字段。
完整程序如下:
#!/usr/bin/env python # -*- coding:utf-8 -*- import pandas as pd import mysql . connector import sys import sys reload ( sys ) sys . setdefaultencoding ( 'utf-8' ) def get_user_info ( user_ids , conn = None ) : '' ' 通过user_id获得用户信息 ' '' user_sql = '' ' SELECT user_id, name FROM user WHERE user_id IN({user_ids}); ' '' . format ( user_ids = ',' . join ( user_ids ) ) user_info = pd . read_sql ( user_sql , conn ) return user_info def get_order_info ( user_ids , conn = None ) : '' ' 通过 用户ID 获得订单信息 ' '' order_sql = '' ' SELECT user_id, order_id, num FROM orders WHERE user_id IN({user_ids}); ' '' . format ( user_ids = ',' . join ( user_ids ) ) order_info = pd . read_sql ( order_sql , conn ) return order_info def get_order_good_info ( order_ids , conn = None ) : '' ' 通过上面获得的 订单ID 获得订单商品信息。 ' '' order_good_sql = '' ' SELECT order_id, good_name FROM order_good WHERE order_id IN ({ids}); ' '' . format ( ids = ',' . join ( order_ids ) ) order_good_info = pd . read_sql ( order_good_sql , conn ) return order_good_info def get_coupon_info ( order_ids , conn = None ) : '' ' 通过 订单ID 获得券信息 ' '' coupon_sql = '' ' SELECT order_id, name FROM coupon WHERE order_id IN({ids}); ' '' . format ( ids = ',' . join ( order_ids ) ) coupon_info = pd . read_sql ( coupon_sql , conn ) return coupon_info def join_data ( func_name , col_name ) : '' ' 添加能通过订单ID查找出来的信息 ' '' def _join_data ( func ) : def __join_data ( * args , * * kargs ) : func_info = func ( * args , * * kargs ) ids = func_info [ col_name ] . astype ( str ) info = eval ( func_name ) ( ids , * * kargs ) new_order = func_info . merge ( info , left_on = col_name , right_on = col_name , how = 'left' ) return new_order return __join_data return _join _data @ join_data ( 'get_coupon_info' , 'order_id' ) @ join_data ( 'get_order_good_info' , 'order_id' ) @ join_data ( 'get_order_info' , 'user_id' ) def get_order_detail ( user_id , conn = None ) : '' ' 拼凑获得订单信息 ' '' user_ids = [ str ( user_id ) ] return get_user_info ( user_ids , conn = conn ) if __name__ == '__main__' : conf = { 'host' : '127.0.0.1' , 'port' : '3306' , 'database' : 'test' , 'user' : 'root' , 'password' : 'root' } conn = mysql . connector . connect ( * * conf ) print get_order_detail ( 10 , conn = conn ) conn . close ( )
最后结果:
user_id name_x order_id num good_name name _y 0 10 HH 1 11111 order_good_1 coupon _1 1 10 HH 1 11111 order_good_2 coupon _1 2 10 HH 2 22222 order_good_3 NaN 3 10 HH 2 22222 order_good_4 NaN 4 10 HH 3 33333 order_good_5 coupon _3 5 10 HH 3 33333 order_good_6 coupon _3 6 10 HH 4 44444 order_good_7 NaN 7 10 HH 4 44444 order_good_8 NaN 8 10 HH 5 55555 order_good_9 coupon _5 9 10 HH 5 55555 order_good_10 coupon_5
源代码:use_dynamic_decorator
现在来看一下我们的业务代码。代码量上少了吧。现在的代码量将会比你的jion还少了吧一个业务只需要在方法上面不端的添加注解(annotation)就好了。
我们来看一下他的应变需求变化的能力。现在业务部需要展现券的信息了,这时我们只需要将如下代码删除了:
@ join_data ( 'get_coupon_info' , 'order_id' )
现在有一个需求,订单需要展示门店的信息(订单和门店是以store_id关联)。这时我们只需要查看是否有人实现过相关的方法比如get_store_info,之后只需要在业务方法get_order_detail的头上加上注解@join_data('get_store_info', 'store_id')。然后就能满足业务的需求了。
而反过来看,如果使用join的方法写的代码。你是不是需要先看懂之前的join是怎么写的,还要考虑我的代码应该要怎么添加。而且join的代码的扩展性无疑是很差的,并且对数据库的查询的并发也会大打折扣。
如果到了现在你们还说使用join能提高开发效率。会增加代码量的。我只能说:对不起,我错了,原谅我的无知吧。