使用Python ConfigParser操作.ini文件时出现KeyError问题及优化方案咨询
一、先解决你的KeyError问题
你遇到的KeyError: 'apps'本质是ConfigParser没有成功读取到你的savefile.ini文件内容,导致找不到对应的配置键。另外,就算读取成功,当前代码还藏着另一个错误——咱们一步步来解决:
1. 核心原因:文件路径不正确
你用了相对路径savedata/savefile.ini,但Python的相对路径是基于程序运行时的当前工作目录,而不是脚本所在的目录。比如如果你在桌面打开命令行,然后运行python Desktop/os/interface.py,当前工作目录是桌面,程序会去Desktop/savedata/savefile.ini找文件,而不是你实际存放的Desktop/os/savedata/savefile.ini,自然找不到配置。
2. 修复路径问题的代码
用os模块构建绝对路径,确保无论在哪里运行脚本都能精准找到配置文件:
from tkinter import * from tkinter import messagebox import datetime import calendar import os.path from configparser import ConfigParser import time root = Tk() root.title('Gamesim') root.geometry('1870x1080') root.attributes('-fullscreen', True) # --- 修改配置读取逻辑 --- # 获取当前脚本所在的绝对目录 script_dir = os.path.dirname(os.path.abspath(__file__)) # 拼接出配置文件的绝对路径 config_path = os.path.join(script_dir, 'savedata', 'savefile.ini') config = ConfigParser() config.read(config_path) # --- 修改结束 ---
3. 另一个潜在错误:字符串转int失败
你的savefile.ini里apps = blue,但代码里apps = int(config['DEFAULT']['apps'])——字符串blue根本无法转成整数,这会触发ValueError。如果apps是用来记录应用数量的,你需要把ini里的apps改成数字(比如apps = 1)。
二、INI配置保存的优化方案
你当前的退出保存逻辑没问题,但可以从稳定性、可读性、健壮性三个方面升级:
1. 用get()方法带默认值,彻底避免KeyError
ConfigParser的get()方法支持设置默认值,就算配置键被误删也不会崩溃:
# 替代原来的直接取值写法 apps = int(config.get('DEFAULT', 'apps', fallback=0)) allapps = config.get('DEFAULT', 'allapps', fallback='') games = int(config.get('DEFAULT', 'games', fallback=0)) allgames = config.get('DEFAULT', 'allgames', fallback='') coins = int(config.get('DEFAULT', 'coins', fallback=0)) image = int(config.get('DEFAULT', 'image', fallback=0)) toolbar_color = config.get('DEFAULT', 'toolbar_color', fallback='black')
2. 确保保存目录存在
如果savedata文件夹被误删,open()会直接报错,所以在保存前先创建目录:
def quit(): global config, config_path, root MsgBox1 = messagebox.askquestion('Are you sure?', 'Are you sure you want to quit?',icon = 'warning') if MsgBox1 == 'yes': # 确保savedata目录存在,不存在就创建 os.makedirs(os.path.dirname(config_path), exist_ok=True) with open(config_path, 'w') as configfile: config.write(configfile) root.destroy()
3. 分Section管理配置
如果你的配置项越来越多,把不同类型的配置分到不同的Section里,可读性会强很多:
# 修改后的savefile.ini [Progress] apps = 1 games = 0 coins = 0 allapps = settings,powerbrowser allgames = [Settings] image = 0 toolbar_color = black
读取时指定对应的Section即可:
apps = int(config.get('Progress', 'apps', fallback=0)) toolbar_color = config.get('Settings', 'toolbar_color', fallback='black')
4. 封装成配置管理类(更整洁的代码)
把配置的加载、保存逻辑封装成类,避免全局变量满天飞,代码也更易维护:
class AppConfig: def __init__(self): self.script_dir = os.path.dirname(os.path.abspath(__file__)) self.config_path = os.path.join(self.script_dir, 'savedata', 'savefile.ini') self.config = ConfigParser() self._load_config() def _load_config(self): # 先创建目录(如果不存在) os.makedirs(os.path.dirname(self.config_path), exist_ok=True) self.config.read(self.config_path) # 设置默认值,确保每个配置项都有兜底 self.config.setdefault('Progress', 'apps', '0') self.config.setdefault('Progress', 'games', '0') self.config.setdefault('Progress', 'coins', '0') self.config.setdefault('Progress', 'allapps', '') self.config.setdefault('Progress', 'allgames', '') self.config.setdefault('Settings', 'image', '0') self.config.setdefault('Settings', 'toolbar_color', 'black') def save(self): with open(self.config_path, 'w') as f: self.config.write(f) # 实例化配置类 app_config = AppConfig() # 读取配置示例 apps = int(app_config.config.get('Progress', 'apps')) toolbar_color = app_config.config.get('Settings', 'toolbar_color') # 退出时调用保存 def quit(): global root, app_config MsgBox1 = messagebox.askquestion('Are you sure?', 'Are you sure you want to quit?',icon = 'warning') if MsgBox1 == 'yes': app_config.save() root.destroy()
内容的提问来源于stack exchange,提问作者marksh16

