关于python3.x:Python3编程实战Tetris机器人数据库操作

28次阅读

共计 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

正文完
 0