> 백엔드 개발 > 파이썬 튜토리얼 > 간편한 Python 구성 파일 버전 3을 향하여

간편한 Python 구성 파일 버전 3을 향하여

Barbara Streisand
풀어 주다: 2024-12-20 14:26:16
원래의
349명이 탐색했습니다.

소개

이 시리즈의 마지막 기사입니다. 이 구현은 이전 기사에서 설명한 보일러 플레이트 코드의 주요 단점을 해결하려고 합니다. 저는 이 구현을 동적 속성 클래스라고 부릅니다.

수업 대표

다음 클래스 다이어그램은 개발자가 이 기능을 사용하는 데 필요한 DynamicConfiguration 재사용 가능 클래스와 지원 데이터 구조를 보여줍니다. 자동 부팅 스트래핑, 누락된 섹션 생성 및 키 값을 포함하여 버전 2의 모든 기본 기능을 계속 제공합니다.

Towards Effortless Python Configuration Files Version 3

개발자 코드 설명

이 클래스를 사용하려는 애플리케이션의 전체 소스 코드를 제시하겠습니다. 이전 3개의 기사에서 논의한 이전 속성을 사용하고 있습니다.

from codeallybasic.DynamicConfiguration import DynamicConfiguration
from codeallybasic.DynamicConfiguration import KeyName
from codeallybasic.DynamicConfiguration import SectionName
from codeallybasic.DynamicConfiguration import Sections
from codeallybasic.DynamicConfiguration import ValueDescription
from codeallybasic.DynamicConfiguration import ValueDescriptions
from codeallybasic.SecureConversions import SecureConversions

from codeallybasic.SingletonV3 import SingletonV3

from ByteSizedPython.ImpostorEnumByName import ImpostorEnumByName
from ByteSizedPython.PhoneyEnumByValue import PhoneyEnumByValue

LOGGER_NAME:       str = 'Tutorial'
BASE_FILE_NAME: str = 'config.ini'
MODULE_NAME:       str = 'version3properties'

DEFAULT_PHONEY_ENUM_BY_VALUE:  PhoneyEnumByValue  = PhoneyEnumByValue.FakeBrenda
DEFAULT_IMPOSTOR_ENUM_BY_NAME: ImpostorEnumByName = ImpostorEnumByName.High

GENERAL_PROPERTIES: ValueDescriptions = ValueDescriptions(
    {
        KeyName('debug'):    ValueDescription(defaultValue='False', deserializer=SecureConversions.secureBoolean),
        KeyName('logLevel'): ValueDescription(defaultValue='Info'),
        KeyName('phoneyEnumByValue'):  ValueDescription(defaultValue=DEFAULT_PHONEY_ENUM_BY_VALUE.value,  enumUseValue=True),
        KeyName('impostorEnumByName'): ValueDescription(defaultValue=DEFAULT_IMPOSTOR_ENUM_BY_NAME.name,  enumUseName=True),
    }
)

DATABASE_PROPERTIES: ValueDescriptions = ValueDescriptions(
    {
        KeyName('dbName'): ValueDescription(defaultValue='dbName'),
        KeyName('dbHost'): ValueDescription(defaultValue='localhost'),
        KeyName('dbPort'): ValueDescription(defaultValue='5342', deserializer=SecureConversions.secureInteger),
    }
)

CONFIGURATION_SECTIONS: Sections = Sections(
    {
        SectionName('General'):  GENERAL_PROPERTIES,
        SectionName('Database'): DATABASE_PROPERTIES,
    }
)

class ConfigurationPropertiesVersion3(DynamicConfiguration, metaclass=SingletonV3):
    def __init__(self):

        self._logger: Logger = getLogger(LOGGER_NAME)

        super().__init__(baseFileName=BASE_FILE_NAME, moduleName=MODULE_NAME, sections=CONFIGURATION_SECTIONS)

로그인 후 복사

45~50번째 줄은 작성해야 하는 코드입니다. 기본적으로 파일 이름, 모듈 이름 및 구성 섹션을 전달하기만 하면 됩니다. 이 섹션 유형은 DynamicConfiguration 모듈에서 제공됩니다.

21-28행과 30-36행은 ValueDescriptions 사전입니다. KeyName은 속성이며 ValueDescription을 가리킵니다. 열거형을 유지하는 방법에 대한 표시가 이전 구현의 데코레이터에서 ValueDescription의 부울 속성으로 이동되었습니다.

구현 코드 설명

DynamicConfiguration의 클래스 다이어그램을 자세히 살펴보면 두 개의 Python magic 메소드가 구현되어 있음을 알 수 있습니다. 그것은 __getattr__(self, name)__ 및 __setattr__(self, name, value)__ 메소드입니다.

  • __getattr__(self, name)__ 클래스 소비자가 존재하지 않는 속성에 액세스하려고 할 때 개발자가 동작을 정의할 수 있도록 합니다.
  • __setattr__(self, name, value)__ 개발자가 속성 할당 동작을 정의할 수 있습니다.

다음은 __getattr__에 대한 코드입니다. 이는 버전 2에서 사용한 데코레이터와 매우 유사합니다. 핵심 작업은 보호된 메서드 _lookupKey()에 대한 14행 호출에서 발생합니다. 속성 검색을 시뮬레이션할 수 있도록 속성에 대한 전체 설명을 반환합니다.

    def __getattr__(self, attrName: str) -> Any:
        """
        Does the work of retrieving the named attribute from the configuration parser

        Args:
            attrName:

        Returns:  The correctly typed value
        """

        self._logger.info(f'{attrName}')

        configParser: ConfigParser     = self._configParser
        result:       LookupResult     = self._lookupKey(searchKeyName=KeyName(attrName))
        valueDescription: ValueDescription = result.keyDescription

        valueStr: str = configParser.get(result.sectionName, attrName)

        if valueDescription.deserializer is not None:
            value: Any = valueDescription.deserializer(valueStr)
        else:
            value = valueStr

        return value

로그인 후 복사

다음은 __setattr__() 구현입니다. 22-27행의 열거형 지원과 30행의 write-through 기능을 확인하세요.

    def __setattr__(self, key: str, value: Any):
        """
        Do the work of writing this back to the configuration/settings/preferences file
        Ignores protected and private variables uses by this class

        Does a "write through" to the backing configuration file (.ini)

        Args:
            key:    The property name
            value:  Its new value
        """

        if key.startswith(PROTECTED_PROPERTY_INDICATOR) or key.startswith(PRIVATE_PROPERTY_INDICATOR):
            super(DynamicConfiguration, self).__setattr__(key, value)
        else:
            self._logger.debug(f'Writing `{key}` with `{value}` to configuration file')

            configParser: ConfigParser  = self._configParser
            result:       LookupResult  = self._lookupKey(searchKeyName=KeyName(key))
            valueDescription: ValueDescription = result.keyDescription

            if valueDescription.enumUseValue is True:
                valueStr: str = value.value
                configParser.set(result.sectionName, key, valueStr)
            elif valueDescription.enumUseName is True:
                configParser.set(result.sectionName, key, value.name)
            else:
                configParser.set(result.sectionName, key, str(value))

            self.saveConfiguration()
로그인 후 복사

속성 액세스 및 수정

속성 접근 및 수정은 버전 2와 동일합니다.

    basicConfig(level=INFO)

    config: ConfigurationPropertiesVersion2 = ConfigurationPropertiesVersion2()

    logger: Logger = getLogger(LOGGER_NAME)

    logger.info(f'{config.debug=}')
    logger.info(f'{config.logLevel=}')
    logger.info(f'{config.phoneyEnumByValue=}')
    logger.info(f'{config.impostorEnumByName=}')
    logger.info('Database Properties Follow')
    logger.info(f'{config.dbName=}')
    logger.info(f'{config.dbHost=}')
    logger.info(f'{config.dbPort=}')
    logger.info('Mutate Enumeration Properties')
    config.phoneyEnumByValue = PhoneyEnumByValue.TheWanderer
    logger.info(f'{config.phoneyEnumByValue=}')
    config.impostorEnumByName = ImpostorEnumByName.Low
    logger.info(f'{config.impostorEnumByName=}')
로그인 후 복사

위 스니펫은 다음과 같은 출력을 생성합니다.

INFO:Tutorial:config.debug='False'
INFO:Tutorial:config.logLevel='Info'
INFO:Tutorial:config.phoneyEnumByValue=<PhoneyEnumByValue.FakeBrenda: 'Faker Extraordinaire'>
INFO:Tutorial:config.impostorEnumByName='High'
INFO:Tutorial:Database Properties Follow
INFO:Tutorial:config.dbName='example_db'
INFO:Tutorial:config.dbHost='localhost'
INFO:Tutorial:config.dbPort=5432
INFO:Tutorial:Mutate Enumeration Properties
INFO:Tutorial:config.phoneyEnumByValue=<PhoneyEnumByValue.TheWanderer: 'The Wanderer'>
INFO:Tutorial:config.impostorEnumByName='Low'
로그인 후 복사

결론

이 글의 소스코드는 여기에 있습니다. 지원 클래스 SingletonV3을 참조하세요.

구현 보기

장점

  • 애플리케이션 속성에 대한 간편한 유형의 안전한 액세스
  • 다양한 구현을 위해 재사용 가능한 상위 클래스
  • 새로운 섹션과 구성 키를 추가하는 데이터 구조 기반 코드
  • 속성에 대한 보일러 플레이트 코드 없음

단점

  • 구현된 실제 속성이 없기 때문에 이에 대한 IDE 지원을 받지 못합니다
  • 또한 키 조회 방법으로 인해 서로 다른 섹션의 서로 다른 키는 동일한 이름을 가질 수 없습니다

위 내용은 간편한 Python 구성 파일 버전 3을 향하여의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿