系列文章入口
《Python3编程实战Tetris机器人》
设计思路
将用户手动玩和AI主动玩游戏的历史记录下来,存入数据库,供前面进行剖析。为了不依赖某个特定的数据系统,设计了一个通用数据库操作接口,以不便在利用层面切换不同的数据库。
接口设计
class BaseDao(object): def select(self, tablename, params={}, fields=None): # 查问接口,参数:数据表名;查问参数(ORM规定融入字典中,请参看下一篇日志);返回数据字段 fields = [] if fields == None else fields # Python的默认参数行为很是不同,会记录上一次调用的后果,有点象其它语言中的动态变量 return dbhelper.select(tablename, params, fields) # 真正的查问实现,dbhelper是针对特定数据库的接口实现 def insert(self, tablename, params={}, fields=[]): # 新增接口,CURD函数的参数模式统一,这种设计不便作rest微服务时,由http的不同拜访形式间接抉择后盾操作方法 if '_id_' in params and len(params) < 2 or '_id_' not in params and len(params) < 1: # 要求提供_id_,约定_id_为所有表的主键 return {"code": 301, "err": "The params is error."} return dbhelper.insert(tablename, params) def update(self, tablename, params={}, fields=[]): if '_id_' not in params or len(params) < 2: return {"code": 301, "err": "The params is error."} return dbhelper.update(tablename, params) def delete(self, tablename, params={}, fields=[]): if '_id_' not in params: return {"code": 301, "err": "The params is error."} return dbhelper.delete(tablename, params) def querySql(self, sql, values = [], params = {}, fields = []): # 手写查问接口 return dbhelper.querySql(sql, values, params, fields) def execSql(self, sql, values = []): # 手写非查问接口 return dbhelper.exec_sql(sql, values) def insertBatch(self, tablename, elements : List): # 批量写入接口 return dbhelper.insertBatch(tablename,elements) def transGo(elements = [], isAsync = False): # 事务接口,待实现 pass
具体实现(Sqlit3)
首先实现了对Sqlit3的操作接口。
间接面对Sqlit3的函数
def exec_sql(sql, values, opType = 0): # opType : 0 - 单条SQL语句; 1 - 批量操作语句;2 - 查问返回数据集; try: # 所有与数据操作都通过这个函数,须要用异样解决封装 flag = False # 是否出错标识变量 error = {} if not os.path.exists("./dist"): # 存储地位目录存在判断 os.mkdir("dist") conn = dbHandle.connect("./dist/log.db") # 连贯数据库或新建 cur = conn.cursor() if opType == 1: # 批量操作 num = cur.executemany(sql, values) else: # 单条语句 num = cur.execute(sql, values) if opType == 2: # 有后果集返回 result = cur.fetchall() else: conn.commit() # print('Sql: ', sql, ' Values: ', values) except Exception as err: # 出错 flag = True error = err print('Error: ', err) finally: conn.close() # 完结解决,并格式化返回后果 if flag: return False, error, num if 'num' in dir() else 0 return True, result if 'result' in dir() else [], len(result) if opType == 2 else num.rowcount if 'num' in dir() else 0
查问函数
这里解说函数骨干,对于在字典中融入ORM的解析,请参看下篇日志。
def select(tablename, params={}, fields=None, sql = None, values = None): where = "" AndJoinStr = ' and ' reserveKeys = {} for rk in ["sort", "search", "page", "size", "sum", "count", "group"]: # 提取保留关键字 for k, v in params.items(): whereExtra = "" if k == "ins": # 保留关键字ins,lks,ors解决 else: flag = False if type(v) == "str": # 不等查问操作解决 elif reserveKeys.get('search'): # 准确查问与含糊查询处理 else: whereExtra += k + " =? " values.append(v) where += whereExtra # 排序、统计、分组和分页等操作解决 rs = exec_sql(sql, values, 2) return {"code": 200, "rows": rs[1], "total": rs[2]}
插入函数
删除和更新与插入相似,这里解说插入函数
def insert(tablename, params={}): sql = "insert into %s ( " % tablename # 骨干 ks = params.keys() vs = [] ps = "" for al in ks: # 解析参数 sql += al + "," # 按插入语句拼接每一个参数 ps += "?," # python的sqlit3封装没法送入list对象来实现元组数据的写入,只能拆开 vs.append(params[al]) sql = sql[:-1] + ") values (" + ps[:-1] + ")" # 去掉最初的逗号,并实现sql语句 rs = exec_sql(sql, vs) # 执行,vs参数中不能嵌套list,比起C++版本的实现,这里有些顺当 if rs[0]: # 返回后果 return {"code": 200, "info": "create success.", "total": rs[2]} else: return {"code": 701, "error": rs[1].args[0], "total": rs[2]}
批量插入
事实证明,一条条的插入效率太低,AI运行时,数据写入跟不上节奏。
def insertBatch(tablename, elements : List): if len(elements) == 0: # 无输出元素,间接退出 return {"code": 201, "info": "There is no elements exist.", "total": 0} elif len(elements) == 1: # 只有一个元素,调用insert实现来实现 return insert(tablename, elements[0]) sql = "insert into %s ( " % tablename isFirst = True # 在循环的第一次,要解决操作字段 vs = [] ps = "" for ele in elements: if isFirst: isFirst = False ks = ele.keys() for al in ks: # 操作字段,只需解决一次 sql += al + "," ps += "?," # 参数批占位符 items = [] for bl in ks: # 按key的程序一一增加写入参数值,字典的拜访程序是不肯定的 items.append(ele[bl]) vs.append(items) sql = sql[:-1] + ") values (" + ps[:-1] + ")" # 最初的拼接 rs = exec_sql(sql, vs, 1) # 执行 if rs[0]: # 返回后果 return {"code": 200, "info": "create success.", "total": rs[2]} else: return {"code": 701, "error": rs[1].args[0], "total": rs[2]}
内容预报
下一篇日志解说融入字典中的ORM规定设计及应用办法,有了这一套规定,无须要再写sql语句。欲后事如何,请继续关注,谢谢!
我的项目地址
https://gitee.com/zhoutk/ptetris或https://github.com/zhoutk/ptetris
运行办法
1. install python3, git2. git clone https://gitee.com/zhoutk/ptetris (or download and unzip source code)3. cd ptetris4. python3 tetrisThis project surpport windows, linux, macOson linux, you must install tkinter first, use this command: sudo apt install python3-tk
相干我的项目
曾经实现了C++版,我的项目地址:
https://gitee.com/zhoutk/qtetris