configparser: lee y escribe archivos INI

Actualizado el: 20/08/2026
Tempo de leitura: 5 minutos
Diagrama de archivos y sistema que representa configuración INI con configparser en Python

El módulo configparser en Python lee y escribe archivos de configuración con estilo INI, organizados en secciones, opciones y valores de texto. Es apropiado para aplicaciones de escritorio, herramientas de línea de comandos, scripts administrativos y programas que necesitan ajustes editables por personas sin recurrir a JSON, YAML o una base de datos.

INI no tiene una única especificación universal. Las aplicaciones difieren en reglas para comentarios, mayúsculas, delimitadores, opciones vacías, valores multilínea e interpolación. Configura el parser deliberadamente y documenta el dialecto aceptado.

Crea un archivo INI básico

[servidor]
host = 127.0.0.1
puerto = 8080
debug = false

[logs]
nivel = INFO
archivo = logs/app.log

Cada encabezado entre corchetes define una sección. Las opciones utilizan = o : como delimitadores por defecto.

Lee la configuración

import configparser

config = configparser.ConfigParser()
leidos = config.read("app.ini", encoding="utf-8")

if not leidos:
    raise FileNotFoundError("app.ini no fue cargado")

host = config["servidor"]["host"]
puerto = config["servidor"].getint("puerto")
debug = config["servidor"].getboolean("debug")

read() ignora silenciosamente archivos que no puede abrir y devuelve la lista de nombres procesados. Comprueba el resultado para archivos obligatorios o usa read_file() con un handle abierto.

Todos los valores son strings

El parser no infiere tipos. Usa getint(), getfloat() y getboolean().

timeout = config["servidor"].getfloat("timeout", fallback=5.0)
workers = config["servidor"].getint("workers", fallback=4)
activo = config["servidor"].getboolean("activo", fallback=True)

getboolean() reconoce yes/no, true/false, on/off y 1/0. No uses bool("false"), porque toda string no vacía es verdadera.

Usa fallback correctamente

En el proxy de sección, el segundo argumento de get() es el fallback:

nivel = config["logs"].get("nivel", "INFO")

En la API del parser, utiliza la palabra clave:

nivel = config.get("logs", "nivel", fallback="INFO")

Los valores heredados de DEFAULT tienen prioridad sobre el fallback, incluso cuando la opción no aparece físicamente en la sección.

Define valores predeterminados

[DEFAULT]
timeout = 10
reintentos = 3

[api]
url = https://api.example.com

[worker]
reintentos = 5

Las opciones de DEFAULT son visibles en todas las secciones. Eliminar una sobrescritura hace reaparecer el valor predeterminado.

Combina archivos por capas

Los archivos leídos más tarde sobrescriben las opciones conflictivas y conservan las demás.

config.read(
    ["defaults.ini", "sitio.ini", "usuario.ini"],
    encoding="utf-8",
)

Un diseño común utiliza defaults versionados, configuración del servidor y overrides personales. Después de cargar todas las capas, valida las opciones obligatorias.

Usa read_file para archivos obligatorios

from pathlib import Path

ruta = Path("defaults.ini")
with ruta.open(encoding="utf-8") as archivo:
    config.read_file(archivo, source=str(ruta))

Los errores de apertura y sintaxis se propagan. El parámetro source mejora los diagnósticos.

Lee strings y diccionarios

read_string() es útil en tests y configuraciones embebidas controladas.

config.read_string("""
[servicio]
url = https://example.com
""", source="defaults embebidos")

read_dict() carga mappings anidados y convierte claves y valores a texto.

config.read_dict({
    "servidor": {"puerto": 8080, "debug": False},
})

Mayúsculas y minúsculas

Los nombres de sección distinguen mayúsculas, pero las opciones no. optionxform() convierte las claves a minúsculas.

config = configparser.ConfigParser()
config.read_string("""
[Seccion]
MiClave = valor
""")
print(list(config["Seccion"]))
# ['miclave']

Para conservar la forma original:

config.optionxform = str

Configúralo antes de leer. Una transformación personalizada debe ser idempotente.

Interpolación básica

ConfigParser usa BasicInterpolation por defecto.

[rutas]
base = /opt/miapp
logs = %(base)s/logs
cache = %(base)s/cache

Escribe %% para un porcentaje literal. La sustitución ocurre al obtener el valor.

Interpolación extendida

ExtendedInterpolation utiliza ${sección:opción} y permite referencias entre secciones.

from configparser import ConfigParser, ExtendedInterpolation

config = ConfigParser(interpolation=ExtendedInterpolation())
[comun]
raiz = /srv/app

[logs]
dir = ${comun:raiz}/logs

Usa $$ para un cifrón literal. Referencias ausentes y ciclos generan excepciones.

Desactiva la interpolación cuando sea necesario

Contraseñas, templates, expresiones regulares y fragmentos shell pueden contener % o $. Si el formato no utiliza sustitución:

config = configparser.ConfigParser(interpolation=None)

En una lectura puntual, usa raw=True.

Añade conversores personalizados

El argumento converters crea nuevos métodos get*.

from pathlib import Path

config = configparser.ConfigParser(
    converters={
        "path": Path,
        "lista": lambda valor: [x.strip() for x in valor.split(",")],
    },
)

ruta_log = config["logs"].getpath("archivo")
origines = config["cors"].getlista("origines")

Convertir no equivale a validar. Comprueba rangos, extensiones, raíces permitidas, existencia y reglas de negocio.

Personaliza valores booleanos

config.BOOLEAN_STATES = {
    "habilitado": True,
    "deshabilitado": False,
}

Un vocabulario localizado puede mejorar legibilidad, pero reduce portabilidad. Documenta las formas aceptadas.

Opciones sin valor

Algunos dialectos usan flags sin delimitador.

config = configparser.ConfigParser(allow_no_value=True)
[recursos]
modo_seguro
auditoria

Estas opciones devuelven None. En Python reciente, continuar una opción sin valor con una línea indentada genera MultilineContinuationError.

Secciones sin nombre

Python 3.13 añadió soporte opcional para opciones antes del primer encabezado.

config = configparser.ConfigParser(allow_unnamed_section=True)
config.read_string("""
clave = valor

[otra]
x = 1
""")
valor = config[configparser.UNNAMED_SECTION]["clave"]

Actívalo únicamente para compatibilidad con un formato existente.

Comentarios y valores multilínea

Por defecto, # y ; introducen comentarios en líneas propias. Los comentarios inline están deshabilitados porque no existe un escape fiable.

Los valores multilínea deben tener mayor indentación:

[mensaje]
texto = primera línea
    segunda línea
    tercera línea

Para archivos editados por personas, considera empty_lines_in_values=False para reducir ambigüedad.

Mantén strict activo

strict=True, valor predeterminado actual, rechaza secciones y opciones duplicadas dentro de una fuente. Detecta errores de escritura y colisiones causadas por la normalización de caja.

Trata errores con claridad

try:
    with open("app.ini", encoding="utf-8") as archivo:
        config.read_file(archivo)
except configparser.MissingSectionHeaderError as error:
    raise RuntimeError("Falta un encabezado de sección") from error
except configparser.DuplicateOptionError as error:
    raise RuntimeError("Opción duplicada") from error
except configparser.InterpolationError as error:
    raise RuntimeError("Interpolación inválida") from error

Incluye fuente y línea en el diagnóstico, pero nunca registres valores secretos.

Escribe configuración

from pathlib import Path

config["servidor"]["puerto"] = "9090"
with Path("app.ini").open("w", encoding="utf-8") as archivo:
    config.write(archivo)

Todos los valores deben ser strings. En Python 3.14, write() genera InvalidWriteError cuando la representación no podría leerse correctamente.

Escribe de forma atómica

No sobrescribas directamente un archivo crítico. Escribe en un temporal del mismo directorio, sincroniza y sustituye el destino.

import os
from pathlib import Path
from tempfile import NamedTemporaryFile

destino = Path("app.ini")
with NamedTemporaryFile("w", encoding="utf-8", dir=destino.parent, delete=False) as temporal:
    config.write(temporal)
    temporal.flush()
    os.fsync(temporal.fileno())
    ruta_temporal = temporal.name
os.replace(ruta_temporal, destino)

Controla permisos y usa locking o un servicio central cuando existan varios escritores.

Los comentarios no se conservan

Leer y escribir nuevamente elimina comentarios y formato original. Si los usuarios mantienen explicaciones importantes, evita reescrituras automáticas o utiliza una biblioteca que preserve el layout.

No guardes secretos en INI

Los archivos INI son texto plano. Contraseñas, tokens y claves privadas deben proceder de un gestor de secretos, variable de entorno protegida o almacén del sistema. Guarda solo el identificador del secreto.

La guía de site en Python explica rutas y entornos; importlib.resources permite distribuir defaults dentro del paquete; y fileinput en Python ayuda con múltiples archivos.

Valida después de leer

def cargar_servidor(config):
    puerto = config["servidor"].getint("puerto")
    if not 1 <= puerto <= 65535:
        raise ValueError("puerto fuera de rango")

    host = config["servidor"].get("host", "127.0.0.1").strip()
    if not host:
        raise ValueError("host vacío")

    return host, puerto

El parser valida estructura y conversiones básicas; la aplicación debe validar semántica.

ConfigParser, TOML y JSON

INI es amigable para configuraciones pequeñas. TOML posee especificación más estricta y tipos nativos. JSON es interoperable, pero no acepta comentarios. Elige según complejidad, ecosistema y necesidad de edición humana.

Buenas prácticas

  • Abre archivos explícitamente como UTF-8.
  • Mantén strict=True.
  • Comprueba archivos obligatorios.
  • Define el comportamiento de mayúsculas.
  • Desactiva interpolación si no la utilizas.
  • Valida cada valor convertido.
  • Escribe actualizaciones de forma atómica.
  • Mantén secretos fuera del INI.

Conclusión

configparser en Python proporciona una interfaz madura para configuración INI con secciones, defaults, capas, interpolación, conversores y acceso como mapping. Funciona mejor cuando el dialecto aceptado es simple y está documentado.

Consulta la documentación oficial de configparser y la documentación de tomllib.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026
    Archivos protegidos que representan extracción segura de TAR con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extrae TAR con seguridad

    Aprende tarfile extraction_filter en Python para extraer archivos TAR con validación, seguridad y control de rutas.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python mostrando avisos controlados con catch_warnings
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: captura warnings en pruebas Python

    Aprende catch_warnings en Python para capturar, probar y controlar avisos con filtros específicos y alcance seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python que representa referencias persistentes de pickle
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serializa referencias externas

    Aprende pickle persistent_id en Python para referencias externas estables, validación, seguridad, rendimiento y compatibilidad.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binario que representa buffers y vistas de memoria en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: cuenta valores sin copiar buffers

    Aprende memoryview.count en Python para contar bytes y valores en buffers sin copias, con formatos, límites y buenas prácticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python y anotaciones de tipos
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evita imports circulares en anotaciones

    Aprende annotationlib en Python para inspeccionar anotaciones diferidas, evitar imports circulares y crear herramientas seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026