configparser는 Python의 표준 라이브러리로, 설정값을 저장하거나 불러올 때 사용됩니다. .ini 형식의 구성 파일을 쉽게 읽고, 쓰고, 수정할 수 있어 애플리케이션 설정 관리에 매우 유용합니다.

소프트웨어 개발에서 구성 관리는 애플리케이션의 동작을 정의하는 데 중요한 역할을 합니다. 구성 설정을 따로 관리하면 개발자는 핵심 기능에 집중할 수 있어 전체 개발 과정이 훨씬 간단해집니다.

예를 들어 웹 애플리케이션의 경우 스테이징, 프로덕션, 개발 등 환경별로 서로 다른 구성 파일을 가질 수 있습니다. 이러한 각 구성은 데이터베이스 연결, API 엔드포인트 및 기능 플래그를 지정하여 애플리케이션이 배포된 위치에 따라 적절하게 작동하도록 할 수 있습니다.

configparser

왜? configparser를 사용할까?

또한 configparser를 사용하면 코드를 수정하지 않고도 다양한 구성으로 손쉽게 전환할 수 있습니다. 이 접근 방식은 자동화된 스크립트가 배포 대상에 따라 적합한 구성 파일을 선택할 수 있는 CI/CD(지속적 통합/지속적 배포) 환경에서 특히 유용합니다.

예를 들어 애플리케이션을 테스트 환경에 배포하는 경우 해당 test.ini 파일을 자동으로 선택하여 올바른 매개변수가 사용되는지 확인할 수 있습니다.

프로그램 규모가 조금만 커져도 설정을 코드에서 분리하는 것이 꼭 필요합니다. 설정 파일을 따로 관리하면 다음과 같은 장점이 있습니다:

  • 코드와 설정 분리 → 재사용성과 유지보수성 향상
  • 환경별 설정 대응 → 개발/운영 환경 분리 가능
  • 재시작 시 연속성 유지 → 이전 설정 상태 유지

가끔 데이터베이스로 설정을 관리하는 경우도 있지만, 이는 과한 설계(over-spec)일 수 있고, 설정 관리의 본래 목적에서 벗어날 수 있습니다.


configparser의 자세한 작동 예제

Python 애플리케이션에서 configparser를 효과적으로 사용하는 방법에 대한 실제 예제를 자세히 살펴보겠습니다. 환경에 따라 서로 다른 데이터베이스에 연결하는 간단한 애플리케이션을 만든다고 가정해 보겠습니다. configure.ini 파일을 다음과 같이 구성할 수 있습니다:

[development]
database_url = localhost:5432
database_name = dev_db

로깅 수준 구성은 컨피파서의 또 다른 훌륭한 사용 사례입니다. 환경마다 다른 로깅 구성을 지정하여 개발에는 상세한 로깅을, 프로덕션에는 최소한의 로깅을 설정할 수 있습니다. 예를 들어

[logging]
level = DEBUG
output_file = app.log

이렇게 하면 개발자는 개발 중에 통찰력 있는 로그를 확보하는 동시에 프로덕션 로그를 깔끔하고 효율적으로 유지할 수 있습니다.

이 구조는 환경에 따라 데이터베이스 연결 설정을 구성합니다. 환경 변수나 명령줄 인수를 통해 원하는 설정 섹션을 선택할 수 있습니다.

import os
import configparser

# 디렉토리 및 파일 경로 설정
base_dir = os.path.dirname(os.path.abspath(__file__))
config_dir = os.path.join(base_dir, 'conf')
config_file = os.path.join(config_dir, 'configure.ini')

# configparser 객체 생성
config = configparser.ConfigParser(interpolation=None,
                                   allow_no_value=True,
                                   delimiters=('='),
                                   strict=False)

# 설정 디렉토리 및 파일 생성
if not os.path.exists(config_dir):
    os.mkdir(config_dir)
if not os.path.isfile(config_file):
    with open(config_file, 'w', encoding='UTF-8') as fd:
        fd.write('[lv1]\nlv2 = Value\n')

# 설정 파일 읽기
config.read(config_file, encoding='UTF-8')

# 섹션 및 항목 출력
print(config.sections(), '\t: print(config.sections())')
for item in config['lv1']:
    print(item, '\t: print(item)')

print(config['lv1']['lv2'], '\t: print(config[\'lv1\'][\'lv2\'])')

# 설정 추가 및 저장
config.set('lv1', 'lv3', 'Value')
with open(config_file, 'w', encoding='UTF-8') as configfile:
   config.write(configfile)

# 파일 전체 출력
with open(config_file, 'r', encoding='UTF-8') as fd:
    line = fd.read()
    print(line)

또한 configparser는 보간을 지원하므로 설정 파일 안에서 값을 재활용할 수 있어 관리가 훨씬 쉬워집니다. 이는 특히 반복되는 설정을 관리하고, 오류를 방지하며, 구성을 반복하지 않는(DRY) 상태로 유지하는 데 유용합니다. 예를 들어

[server]
host = localhost
port = 8080
url = http://${server:host}:${server:port}/api

여기서 URL 설정은 같은 섹션에 정의된 호스트 및 포트 값을 사용하므로 유지 관리가 쉽습니다.

설정 파일 (configure.ini) 예시

[lv1]
lv2 = Value
lv3 = Value
  • 항상 key = value 형태로 설정을 작성합니다.
  • Section을 기준으로 그룹화 → 동일 키 이름이 다른 섹션에서 사용 가능

주요 특징 요약

기능설명
.ini 포맷 지원섹션, 키, 값 구조로 구성
설정 읽기/쓰기파일에서 값을 읽고 수정/저장 가능
유연성파일 자동 생성, 기본값 정의 등 지원
내장 라이브러리설치 없이 바로 사용 가능

사용 예시

  1. 애플리케이션이 중소규모인 경우
  2. 빠르고 가벼운 구성 형식이 필요한 경우
  3. 사람이 읽을 수 있는 설정 파일이 필요한 경우
  4. 배포 또는 환경 설정을 관리하는 경우

단점 및 대안

단점설명
중첩 구조 표현 불가계층적 데이터 구조에는 부적합
리스트, 딕셔너리 미지원JSON/YAML에 비해 유연성 떨어짐



API 키나 비밀번호와 같은 민감한 정보를 처리할 때는 ini 파일을 보호하는 것이 중요합니다. configparser는 기본 암호화를 제공하지 않지만 환경 변수에서 이러한 민감한 값을 참조하는 것이 일반적인 관행입니다. 예를 들어 데이터베이스 비밀번호에 대한 환경 변수를 설정한 다음 구성에서 이를 참조할 수 있습니다:

[database]
user = myuser
password = ${env:DATABASE_PASSWORD}

이렇게 하면 민감한 정보가 코드베이스와 구성 파일에 포함되지 않아 보안 모범 사례를 준수할 수 있습니다.

복잡한 설정이 필요한 경우 JSON이나 YAML을 사용하는 것이 더 적절합니다.
실제로 최근에는 클라우드 기반 프로그램에서 YAML이 많이 사용되고 있습니다.


configparser vs JSON vs YAML 를 비교 분석

광범위한 구성 관리가 필요한 시나리오에서는 argparse와 같은 라이브러리를 사용하여 명령줄 인자로 configparser를 보완하는 것을 고려하세요. 이 조합을 사용하면 하드코딩된 값 없이도 런타임에 유연하게 구성을 조정할 수 있습니다. 예를 들어 환경 이름을 명령줄 인수로 전달하고 적절한 구성을 동적으로 로드 할 수 있습니다.

세 가지 설정 파일 포맷인 configparser, JSON, YAML은 각각 장단점이 뚜렷합니다. 간단하게 비교해 드릴게요.

요약 비교

항목configparser (.ini)JSONYAML
구조섹션 기반 (key-value)객체/배열 기반들여쓰기 기반 계층 구조
문법 간결성매우 간단비교적 간결가장 간결하고 읽기 쉬움
표현력낮음 (계층 구조 불편)중간 (중첩 표현 가능)높음 (복잡한 구조 쉽게 표현)
인간 친화성높음낮음 (중괄호/콤마 많음)매우 높음 (직관적인 문법)
주석 지원OXO
파이썬 지원표준 라이브러리 (configparser)표준 라이브러리 (json)외부 라이브러리 필요 (PyYAML)
사용 용도단순 설정 파일웹 API, 데이터 교환복잡 설정파일, DevOps

언제 어떤 걸 써야 할까?

configparser (ini)

  • 간단한 데스크탑/스크립트 설정에 적합
  • 구조가 단순함 (섹션 > 키=값)
  • 중첩 구조가 필요 없는 설정에서 가장 빠르고 직관적
[database]
host = localhost
port = 5432

JSON

  • 웹/모바일 앱 설정이나 데이터 전송에 적합
  • 중첩 구조 표현 가능하지만 사람이 편하게 읽기엔 불편
  • 주석이 없어 설명 첨부 어려움
{
  "database": {
    "host": "localhost",
    "port": 5432
  }
}

YAML

  • 복잡한 설정파일 (예: Kubernetes, GitHub Actions)에 적합
  • 들여쓰기만으로 구조 표현 가능, 주석도 가능
  • 사람이 읽기 가장 쉬움, 실수로 인한 파싱 오류는 주의
database:
  host: localhost
  port: 5432
  • 간단한 설정이면configparser
  • 기계 간 데이터 교환이면JSON
  • 사람이 편하게 설정 관리하려면YAML

마무리

간단한 구조의 설정 파일을 관리할 때 configparser 는 빠르고 효율적인 선택지입니다. Python에 기본 내장되어 있어 별도 패키지 설치 없이 사용할 수 있으며, 작은 프로젝트나 자동화 스크립트, CLI 도구 개발에 특히 유용합니다.

복잡한 설정이 아니라면, 여전히 .ini 포맷은 간결하고 사람이 읽기 쉬운 형식으로 사랑받고 있습니다.

마지막으로, 구성에 대한 간단한 접근 방식이 필요한 많은 중소규모 프로젝트에서 configparser를 사용하는 것이 좋습니다. 복잡한 구성을 가진 대규모 프로젝트의 경우 보다 강력한 구성 관리 시스템을 평가해야 할 수도 있습니다. 하지만 configparser를 마스터하면 모든 소프트웨어 개발자에게 견고한 기반을 제공하여 유지 관리 가능한 애플리케이션을 설계할 수 있는 능력을 향상시킬 수 있습니다.

에러 및 수정사항

1. MissingSectionHeaderError

원인: .ini 파일에 [section] 헤더가 없음
예시:

key = value  # 섹션 없이 바로 키-값 사용

해결:

[DEFAULT]
key = value

2. ParsingError

원인: 문법 오류, 예를 들어 등호(=) 빠짐 또는 잘못된 줄바꿈
예시:

[section]
key value  # 등호 빠짐

해결:

[section]
key = value

3. DuplicateSectionError

원인: 동일한 섹션 이름이 중복됨
예시:

[server]
ip = 127.0.0.1

[server]  # 중복
port = 8080

해결: 섹션 이름을 하나로 통합하거나 고유하게 변경


4. NoSectionError

원인: 존재하지 않는 섹션에서 값을 불러올 때
해결: read() 전에 해당 섹션이 존재하는지 확인하고, 없으면 add_section() 사용

if not config.has_section("user"):
    config.add_section("user")

5. NoOptionError

원인: 존재하지 않는 키를 불러올 때
해결:

  • 존재 여부 확인 후 처리
if config.has_option("user", "name"):
    name = config.get("user", "name")
  • 또는 기본값 설정
name = config.get("user", "name", fallback="unknown")

By Mark

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다