共计 4086 个字符,预计需要花费 11 分钟才能阅读完成。
系列文章入口
《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, git
2. git clone https://gitee.com/zhoutk/ptetris (or download and unzip source code)
3. cd ptetris
4. python3 tetris
This project surpport windows, linux, macOs
on linux, you must install tkinter first, use this command:
sudo apt install python3-tk
相干我的项目
曾经实现了 C ++ 版,我的项目地址:
https://gitee.com/zhoutk/qtetris
正文完