Python结合SQLite建表实现蒙特卡洛求π时触发类型转换报错
报错原因定位
你遇到的报错核心是首次运行的判断逻辑完全失效,具体逻辑链是:
- SQLite 执行
SELECT MAX(字段)查询空表时,不会返回空结果,而是返回一个包含None的元组,比如查询Pi表的最大parses值,空表时cur.fetchone()会得到(None,),而不是Python层面的None值 - 你写的判断条件
if parses is None:永远不会命中,哪怕Pi表是全新的空表,代码也会强行走到else分支 - 进入else分支后查询
MAX(incircle),拿到的列值是None,直接转成int就会抛出你看到的类型错误 - 除此之外还有两处连带的逻辑bug,就算解决了当前报错,后续运行也会触发其他异常:
- 插入XY表时,直接把x、y的浮点数值传给了
x_id/y_id这两个整型字段,字段类型不匹配 - Pi表给
incircle字段加了UNIQUE约束,后续累计计算时如果数值和历史记录重复,会被INSERT OR IGNORE直接跳过,无法保存新的计算结果
- 插入XY表时,直接把x、y的浮点数值传给了
针对性修改步骤
1. 修正空表判断逻辑,直接解决当前报错
替换原来的历史值查询和分支判断部分代码:
# 一次性查询历史累计的总点数、圆内点数,避免重复查库 cur.execute('''SELECT MAX(parses), MAX(incircle) FROM Pi''') # 空表时返回的是(None, None),不是None本身 max_total, max_circle = cur.fetchone() runs = input('Enter number of points: ') print('***Started calculating***') n = int(runs) # 修正判断条件:判断列值是否为None,而不是判断fetch的结果是否为None if max_total is None: num_point_circle = 0 num_point_total = 0 print('###STARTING FROM SCRATCH###') else: num_point_circle = int(max_circle) num_point_total = int(max_total) print(f'###CONTINUE FROM {num_point_total} PARSES###')
2. 修正XY表的字段赋值逻辑
原来的代码错误地把x、y的数值直接传给了存自增ID的整型字段,替换循环内的插入逻辑:
try: for i in range(n): x = random.uniform(0, 1) y = random.uniform(0, 1) # 插入x值到X表 cur.execute('INSERT OR IGNORE INTO X (x_value) VALUES (?)', (x,)) # 不管是新插入还是已存在的x值,查询对应的X表id cur.execute('SELECT id FROM X WHERE x_value = ?', (x,)) x_id = cur.fetchone()[0] # 同理处理y值 cur.execute('INSERT OR IGNORE INTO Y (y_value) VALUES (?)', (y,)) cur.execute('SELECT id FROM Y WHERE y_value = ?', (y,)) y_id = cur.fetchone()[0] distance = x**2 + y**2 if distance <= 1: num_point_circle += 1 loc = 'Inside Circle' else: loc = 'Outside Circle' # 用查询到的id插入XY表 cur.execute('INSERT OR IGNORE INTO XY (x_id, y_id, loc) VALUES (?,?,?)', (x_id, y_id, loc)) num_point_total += 1
3. 调整Pi表的约束定义
去掉incircle字段不必要的UNIQUE约束,避免后续累计值重复时被跳过插入:
cur.execute('''CREATE TABLE IF NOT EXISTS Pi (id INTEGER PRIMARY KEY, pi_value REAL, Accuracy FLOAT, parses INTEGER, incircle INTEGER)''')
4. 收尾优化
在代码所有逻辑执行完毕后,加一行数据库关闭语句,避免出现SQLite文件锁的问题:
conn.close()
内容的提问来源于stack exchange,提问作者Tvergos
相关产品推荐
相关产品推荐

