Python Complete Guide to INI Configuration File Handling: Make Your App Configuration Management More Elegant
In Python development on the Windows platform, we often need to deal with various configuration files. Whether it's a desktop application, automation script, or HMI program, proper configuration management is key to project success. Today we'll dive into the most classic configuration file format in Python — the INI file — and its read/write operations. This article starts from real development needs and, through rich code examples, helps you master all INI file handling techniques to easily handle various configuration management scenarios.
Among many configuration file formats, INI files have unique advantages:
Clear structure: Use sections and key-value pairs; even non-technical users can easily understand it
Strong compatibility: Native support on Windows; many legacy applications use this format
Good readability: Plain text format, supports comments, easy to maintain and debug
A typical INI file structure:
Ini; 这是注释
[database]
host = localhost
port = 3306
username = admin
password = 123456
[logging]
level = INFO
file_path = ./logs/app.log
max_size = 10MB
The Python standard library provides the configparser module, the first-choice tool for handling INI files. Let's start from basic usage:
Pythonimport configparser
def read_config():
# Create ConfigParser object
config = configparser.ConfigParser()
# Read configuration file
config.read('config.ini', encoding='utf-8')
# Get all section names
sections = config.sections()
print(f"配置文件包含的节: {sections}")
# Read all key-value pairs of a specific section
db_config = dict(config['database'])
print(f"数据库配置: {db_config}")
# Read specific configuration items
host = config.get('database', 'host')
port = config.getint('database', 'port') # Automatically converted to int
print(f"数据库地址: {host}:{port}")
return config
# Usage example
if __name__ == "__main__":
config = read_config()

Pythonimport configparser
def create_config():
config = configparser.ConfigParser()
# Add database section
config.add_section('database')
config.set('database', 'host', 'localhost')
config.set('database', 'port', '3306')
config.set('database', 'username', 'admin')
config.set('database', 'password', '123456')
# Add logging section
config.add_section('logging')
config.set('logging', 'level', 'INFO')
config.set('logging', 'file_path', './logs/app.log')
config.set('logging', 'max_size', '10MB')
# Write to file
with open('config.ini', 'w', encoding='utf-8') as f:
config.write(f)
print("配置文件创建成功!")
def update_config():
config = configparser.ConfigParser()
config.read('config.ini', encoding='utf-8')
# Modify existing configuration
config.set('database', 'password', 'new_password')
# Add new configuration items
if not config.has_section('app'):
config.add_section('app')
config.set('app', 'version', '1.0.0')
config.set('app', 'debug', 'False')
# Save changes
with open('config.ini', 'w', encoding='utf-8') as f:
config.write(f)
print("配置更新完成!")
create_config()
update_config()

Let's demonstrate best practices with a complete configuration management class:
Pythonimport configparser
import os
from pathlib import Path
class ConfigManager:
def __init__(self, config_file='app_config.ini'):
self.config_file = config_file
self.config = configparser.ConfigParser()
# Ensure the config file exists
if not os.path.exists(config_file):
self._create_default_config()
else:
self.load_config()
def _create_default_config(self):
"""Create default config file"""
# App basic configuration
self.config.add_section('app')
self.config.set('app', 'title', 'Python桌面应用')
self.config.set('app', 'version', '1.0.0')
self.config.set('app', 'window_width', '1024')
self.config.set('app', 'window_height', '768')
self.config.set('app', 'auto_save', 'True')
# Database configuration
self.config.add_section('database')
self.config.set('database', 'driver', 'sqlite')
self.config.set('database', 'path', './data/app.db')
self.config.set('database', 'backup_interval', '24')
# User preferences
self.config.add_section('preferences')
self.config.set('preferences', 'theme', 'light')
self.config.set('preferences', 'language', 'zh-CN')
self.config.set('preferences', 'font_size', '12')
self.save_config()
print("已创建默认配置文件")
def load_config(self):
"""Load config file"""
try:
self.config.read(self.config_file, encoding='utf-8')
print("配置文件加载成功")
except Exception as e:
print(f"配置文件加载失败: {e}")
self._create_default_config()
def save_config(self):
"""Save config to file"""
try:
with open(self.config_file, 'w', encoding='utf-8') as f:
self.config.write(f)
print("配置保存成功")
except Exception as e:
print(f"配置保存失败: {e}")
def get_app_config(self):
"""Get application config"""
return {
'title': self.config.get('app', 'title'),
'version': self.config.get('app', 'version'),
'window_size': (
self.config.getint('app', 'window_width'),
self.config.getint('app', 'window_height')
),
'auto_save': self.config.getboolean('app', 'auto_save')
}
def get_database_config(self):
"""Get database config"""
return {
'driver': self.config.get('database', 'driver'),
'path': self.config.get('database', 'path'),
'backup_interval': self.config.getint('database', 'backup_interval')
}
def update_preference(self, key, value):
"""Update user preference"""
self.config.set('preferences', key, str(value))
self.save_config()
def get_preference(self, key, default=None):
"""Get user preference"""
try:
return self.config.get('preferences', key)
except (configparser.NoSectionError, configparser.NoOptionError):
return default
def backup_config(self, backup_path=None):
"""Backup config file"""
if backup_path is None:
backup_path = f"{self.config_file}.backup"
try:
import shutil
shutil.copy2(self.config_file, backup_path)
print(f"配置文件已备份到: {backup_path}")
return True
except Exception as e:
print(f"配置备份失败: {e}")
return False
# Usage example
def demo_config_manager():
# Create config manager instance
config_mgr = ConfigManager()
# Get config info
app_config = config_mgr.get_app_config()
print(f"应用配置: {app_config}")
db_config = config_mgr.get_database_config()
print(f"数据库配置: {db_config}")
# Update user preferences
config_mgr.update_preference('theme', 'dark')
config_mgr.update_preference('font_size', '14')
# Get preference settings
theme = config_mgr.get_preference('theme')
font_size = config_mgr.get_preference('font_size')
print(f"当前主题: {theme}, 字体大小: {font_size}")
# Backup config
config_mgr.backup_config()
if __name__ == "__main__":
demo_config_manager()

For sensitive information (like passwords), it's not recommended to store them directly in INI files. You can combine simple encoding:
Pythonimport base64
import configparser
import os
class SecureConfigManager:
def __init__(self, config_file='secure_config.ini'):
self.config_file = config_file
self.config = configparser.ConfigParser()
self.load_config()
def encode_password(self, password):
"""Simple password encoding (for demo only; use stronger methods in real projects)"""
return base64.b64encode(password.encode()).decode()
def decode_password(self, encoded_password):
"""Decode password"""
return base64.b64decode(encoded_password.encode()).decode()
def set_secure_value(self, section, key, value):
"""Set a value that needs encoding"""
if not self.config.has_section(section):
self.config.add_section(section)
encoded_value = self.encode_password(value)
self.config.set(section, key, encoded_value)
self.save_config()
def get_secure_value(self, section, key):
"""Get decoded value"""
try:
encoded_value = self.config.get(section, key)
return self.decode_password(encoded_value)
except Exception as e:
print(f"获取安全值失败: {e}")
return None
def load_config(self):
if os.path.exists(self.config_file):
self.config.read(self.config_file, encoding='utf-8')
def save_config(self):
with open(self.config_file, 'w', encoding='utf-8') as f:
self.config.write(f)
# Usage example
secure_config = SecureConfigManager()
secure_config.set_secure_value('database', 'password', 'my_secret_password')
print(f"已保存密码: {secure_config.get_secure_value('database', 'password')}")
password = secure_config.get_secure_value('database', 'password')
print(f"解码后的密码: {password}")

Pythondef create_config_template():
"""Create a configuration file template for users to customize"""
template = """
; ===========================================
; 应用程序配置文件模板
; ===========================================
[app]
; 应用程序基本信息
title = 我的Python应用
version = 1.0.0
window_width = 1024
window_height = 768
auto_save = True
[database]
; 数据库连接配置
driver = sqlite
path = ./data/app.db
backup_interval = 24
[preferences]
; 用户偏好设置
theme = light
language = zh-CN
font_size = 12
[logging]
; 日志配置
level = INFO
file_path = ./logs/app.log
max_file_size = 10MB
backup_count = 5
"""
with open('config_template.ini', 'w', encoding='utf-8') as f:
f.write(template)
print("配置模板已创建,请根据需要修改后重命名为config.ini")


Pythondef validate_config(config_file='config.ini'):
"""Validate the integrity of the configuration file"""
required_sections = ['app', 'database', 'preferences']
required_keys = {
'app': ['title', 'version', 'window_width', 'window_height'],
'database': ['driver', 'path'],
'preferences': ['theme', 'language']
}
config = configparser.ConfigParser()
try:
config.read(config_file, encoding='utf-8')
# Check required sections
missing_sections = []
for section in required_sections:
if not config.has_section(section):
missing_sections.append(section)
if missing_sections:
print(f"缺少必需的配置节: {missing_sections}")
return False
# Check required keys
missing_keys = {}
for section, keys in required_keys.items():
section_missing = []
for key in keys:
if not config.has_option(section, key):
section_missing.append(key)
if section_missing:
missing_keys[section] = section_missing
if missing_keys:
print(f"缺少必需的配置项: {missing_keys}")
return False
print("配置文件验证通过!")
return True
except Exception as e:
print(f"配置文件验证失败: {e}")
return False



In real Windows desktop app development, configuration management is usually tightly integrated with GUI frameworks:
Pythonimport os
import tkinter as tk
from tkinter import ttk, messagebox
import configparser
class SettingsWindow:
def __init__(self, parent, config_manager):
self.parent = parent
self.config_mgr = config_manager
self.window = tk.Toplevel(parent)
self.window.title("应用设置")
self.window.geometry("400x300")
self.create_widgets()
self.load_settings()
def create_widgets(self):
# Create notebook for grouped settings
notebook = ttk.Notebook(self.window)
# App settings page
app_frame = ttk.Frame(notebook)
notebook.add(app_frame, text="应用设置")
# Window size settings
ttk.Label(app_frame, text="窗口宽度:").grid(row=0, column=0, sticky='w', padx=5, pady=5)
self.width_var = tk.StringVar()
ttk.Entry(app_frame, textvariable=self.width_var).grid(row=0, column=1, padx=5, pady=5)
ttk.Label(app_frame, text="窗口高度:").grid(row=1, column=0, sticky='w', padx=5, pady=5)
self.height_var = tk.StringVar()
ttk.Entry(app_frame, textvariable=self.height_var).grid(row=1, column=1, padx=5, pady=5)
# Auto save setting
self.auto_save_var = tk.BooleanVar()
ttk.Checkbutton(app_frame, text="启用自动保存",
variable=self.auto_save_var).grid(row=2, column=0, columnspan=2, sticky='w', padx=5, pady=5)
# Preferences page
pref_frame = ttk.Frame(notebook)
notebook.add(pref_frame, text="偏好设置")
# Theme setting
ttk.Label(pref_frame, text="主题:").grid(row=0, column=0, sticky='w', padx=5, pady=5)
self.theme_var = tk.StringVar()
theme_combo = ttk.Combobox(pref_frame, textvariable=self.theme_var,
values=['light', 'dark'], state='readonly')
theme_combo.grid(row=0, column=1, padx=5, pady=5)
# Font size setting
ttk.Label(pref_frame, text="字体大小:").grid(row=1, column=0, sticky='w', padx=5, pady=5)
self.font_size_var = tk.StringVar()
font_combo = ttk.Combobox(pref_frame, textvariable=self.font_size_var,
values=['10', '12', '14', '16', '18'], state='readonly')
font_combo.grid(row=1, column=1, padx=5, pady=5)
notebook.pack(fill='both', expand=True, padx=10, pady=10)
# Button frame
button_frame = ttk.Frame(self.window)
button_frame.pack(fill='x', padx=10, pady=5)
ttk.Button(button_frame, text="保存", command=self.save_settings).pack(side='right', padx=5)
ttk.Button(button_frame, text="取消", command=self.window.destroy).pack(side='right', padx=5)
ttk.Button(button_frame, text="恢复默认", command=self.reset_defaults).pack(side='left')
def load_settings(self):
"""Load settings from config file"""
app_config = self.config_mgr.get_app_config()
self.width_var.set(str(app_config['window_size'][0]))
self.height_var.set(str(app_config['window_size'][1]))
self.auto_save_var.set(app_config['auto_save'])
self.theme_var.set(self.config_mgr.get_preference('theme', 'light'))
self.font_size_var.set(self.config_mgr.get_preference('font_size', '12'))
def save_settings(self):
"""Save settings to config file"""
try:
# Save app settings
self.config_mgr.config.set('app', 'window_width', self.width_var.get())
self.config_mgr.config.set('app', 'window_height', self.height_var.get())
self.config_mgr.config.set('app', 'auto_save', str(self.auto_save_var.get()))
# Save preferences
self.config_mgr.update_preference('theme', self.theme_var.get())
self.config_mgr.update_preference('font_size', self.font_size_var.get())
self.config_mgr.save_config()
messagebox.showinfo("成功", "设置已保存!")
self.window.destroy()
except Exception as e:
messagebox.showerror("错误", f"保存设置失败: {e}")
def reset_defaults(self):
"""Reset to default settings"""
self.width_var.set('1024')
self.height_var.set('768')
self.auto_save_var.set(True)
self.theme_var.set('light')
self.font_size_var.set('12')
class ConfigManager:
def __init__(self, config_path='app_settings.ini'):
self.config_path = config_path
self.config = configparser.ConfigParser()
self.load_config()
def load_config(self):
if not os.path.exists(self.config_path):
# Initialize default config
self.config['app'] = {
'window_width': '1024',
'window_height': '768',
'auto_save': 'True'
}
self.config['preference'] = {
'theme': 'light',
'font_size': '12'
}
self.save_config()
else:
self.config.read(self.config_path, encoding='utf-8')
def save_config(self):
with open(self.config_path, 'w', encoding='utf-8') as configfile:
self.config.write(configfile)
def get_app_config(self):
app_cfg = self.config['app']
width = int(app_cfg.get('window_width', '1024'))
height = int(app_cfg.get('window_height', '768'))
auto_save = app_cfg.get('auto_save', 'True') == 'True'
return {'window_size': (width, height), 'auto_save': auto_save}
def get_preference(self, key, default=None):
return self.config['preference'].get(key, default)
def update_preference(self, key, value):
self.config['preference'][key] = value
if __name__ == '__main__':
root = tk.Tk()
root.withdraw()
config_mgr = ConfigManager() # Instantiate config manager
s = SettingsWindow(root, config_mgr)
s.window.mainloop()

Through this in-depth tutorial, we have mastered the core skills for handling INI configuration files in Python:
🔑 Core skill mastery: From basic configparser usage to advanced features, including various methods to read, write, and modify config files, enabling you to handle configuration management needs of varying complexity.
💼 Practical experience: The complete ConfigManager class and GUI integration examples demonstrate real-project best practices, including security considerations, configuration validation, template creation, and other advanced features.
🚀 Improved development efficiency: With these techniques, your Python apps will have more professional configuration management capabilities, improving user experience and code maintainability.
Although INI configuration files look simple, they are an indispensable skill in Python development on the Windows platform. Whether it's desktop apps, automation tools, or HMI programs, good configuration management makes your projects more professional and user-friendly. I hope this article helps you advance further on your Python development journey!
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!