前の記事では、アプリケーションの構成値を管理するためのシミュレートされたプロパティ データクラスを作成することができました。 ただし、これは基本的に単なるテンプレートであり、用途ごとに再実装する必要がありました。 私の仕事のバージョン 2 では、再利用可能なクラスを実装することに成功しました。
次のクラス図は、基本的な再利用可能なクラスと、開発者がこの機能を使用するために必要なデータ構造を示しています。
開発者は、次のように構成プロパティをサブクラス化することでプロセスを開始します。
BASE_FILE_NAME: str = 'config.ini' MODULE_NAME: str = 'version2properties' class ConfigurationPropertiesVersion2(ConfigurationProperties, metaclass=SingletonV3): def __init__(self): self.logger: Logger = getLogger(LOGGER_NAME) super().__init__(baseFileName=BASE_FILE_NAME, moduleName=MODULE_NAME, sections=CONFIGURATION_SECTIONS) self._configParser.optionxform = self._toStr # type: ignore self._loadConfiguration()
super への呼び出しにより、構成ファイルへの完全修飾パスが作成されます。 このコードは、XDG Base Directory 仕様のサブセットに従っています。 このコードは、最初に XDG_CONFIG_HOME を試行し、次に HOME を試行し、両方とも失敗した場合は最後に現在のディレクトリを使用します。 13 行目で、開発者は保護されたメソッドを呼び出して、構成パーサーを準備します。 さらに、その呼び出しは
以前の機能により、多くの再利用可能なコードとブートストラップ構成ファイルが生成されます。 さらに、アプリケーション コード ベース全体でクラスをインスタンス化する際の作成コストを軽減するために、クラスをシングルトンにします。
スーパーコールのパラメータセクションに注目してください。 このセクションの定義は次のようになります:
from codeallybasic.ConfigurationProperties import Sections CONFIGURATION_SECTIONS: Sections = Sections( { SectionName('General'): SECTION_GENERAL, SectionName('Database'): SECTION_DATABASE, } )
上記はキーがセクション名、値がセクションである辞書です。
セクションは、ConfigurationNameValue エントリの単なるリストです。 ConfigurationNameValue は、PropertyName とそのデフォルト値の 2 つの値を持つデータ クラスです。ここにセクションがあります。
from codeallybasic.ConfigurationProperties import Section from codeallybasic.ConfigurationProperties import ConfigurationNameValue from codeallybasic.ConfigurationProperties import PropertyName SECTION_GENERAL: Section = Section( [ ConfigurationNameValue(name=PropertyName('debug'), defaultValue='False'), ConfigurationNameValue(name=PropertyName('logLevel'), defaultValue='Info'), ConfigurationNameValue(name=PropertyName('phoneyEnumByValue'), defaultValue=DEFAULT_PHONEY_ENUM_BY_VALUE.value), ConfigurationNameValue(name=PropertyName('impostorEnumByName'), defaultValue=DEFAULT_IMPOSTOR_ENUM_BY_NAME.name), ] ) SECTION_DATABASE: Section = Section( [ ConfigurationNameValue(name=PropertyName('dbName'), defaultValue='example_db'), ConfigurationNameValue(name=PropertyName('dbHost'), defaultValue='localhost'), ConfigurationNameValue(name=PropertyName('dbPort'), defaultValue='5432'), ] )
2 つの新しい列挙プロパティを指定したことに注目してください。 永続化したいのは value で、もう 1 つはその名前です。
ここに列挙型の定義があります。
class PhoneyEnumByValue(Enum): TheWanderer = 'The Wanderer' Mentiroso = 'Mentiroso' FakeBrenda = 'Faker Extraordinaire' NotSet = 'Not Set' @classmethod def deSerialize(cls, value: str) -> 'PhoneyEnumByValue': @classmethod def deSerialize(cls, value: str) -> 'PhoneyEnumByValue': match value: case PhoneyEnumByValue.TheWanderer.value: phoneyEnum: PhoneyEnumByValue = PhoneyEnumByValue.TheWanderer case PhoneyEnumByValue.Mentiroso.value: phoneyEnum = PhoneyEnumByValue.Mentiroso case PhoneyEnumByValue.FakeBrenda.value: phoneyEnum = PhoneyEnumByValue.FakeBrenda case _: raise Exception('Unknown PhoneyEnumByValue') return phoneyEnum class ImpostorEnumByName(Enum): Low = 0.1 Medium = 0.5 High = 1.0 NotSet = -1.0
これらが開発者クラスのプロパティ定義にどのような影響を与えるかを見ていきます
文字列プロパティは次のように定義されます。
BASE_FILE_NAME: str = 'config.ini' MODULE_NAME: str = 'version2properties' class ConfigurationPropertiesVersion2(ConfigurationProperties, metaclass=SingletonV3): def __init__(self): self.logger: Logger = getLogger(LOGGER_NAME) super().__init__(baseFileName=BASE_FILE_NAME, moduleName=MODULE_NAME, sections=CONFIGURATION_SECTIONS) self._configParser.optionxform = self._toStr # type: ignore self._loadConfiguration()
私たちが取り除いたのは、configParser にアクセスして値を取得および設定するための定型文です。 私たちが追加したのは、configurationGetter デコレータとconfigurationSetter デコレータです。 デコレータの実装の詳細については説明せず、読者のための演習として残しておきます。 これらのデコレーターは、構成パーサーとの対話を処理して、値を取得および設定します。 値を設定すると、configurationSetter デコレータが ライトスルー を実行します。
開発者は整数プロパティを次のように定義します。
from codeallybasic.ConfigurationProperties import Sections CONFIGURATION_SECTIONS: Sections = Sections( { SectionName('General'): SECTION_GENERAL, SectionName('Database'): SECTION_DATABASE, } )
configurationGetter デコレーターにはオプションのパラメーターがあることに注意してください。 これは、文字列プロパティ値を取得し、呼び出し側プロパティに戻る前に、それを適切な型指定された値に変換する関数です。 これは float プロパティに適用できます。
列挙名を永続化する列挙プロパティは次のように定義されます:
from codeallybasic.ConfigurationProperties import Section from codeallybasic.ConfigurationProperties import ConfigurationNameValue from codeallybasic.ConfigurationProperties import PropertyName SECTION_GENERAL: Section = Section( [ ConfigurationNameValue(name=PropertyName('debug'), defaultValue='False'), ConfigurationNameValue(name=PropertyName('logLevel'), defaultValue='Info'), ConfigurationNameValue(name=PropertyName('phoneyEnumByValue'), defaultValue=DEFAULT_PHONEY_ENUM_BY_VALUE.value), ConfigurationNameValue(name=PropertyName('impostorEnumByName'), defaultValue=DEFAULT_IMPOSTOR_ENUM_BY_NAME.name), ] ) SECTION_DATABASE: Section = Section( [ ConfigurationNameValue(name=PropertyName('dbName'), defaultValue='example_db'), ConfigurationNameValue(name=PropertyName('dbHost'), defaultValue='localhost'), ConfigurationNameValue(name=PropertyName('dbPort'), defaultValue='5432'), ] )
適切なデコレータを使用することに加えて、列挙名を永続化するには enumUseName パラメータを使用し、それを True に設定することに注意してください。
以下は、開発者が値を永続化したい列挙型プロパティです。 setter デコレーターが列挙型であることを示していることに注意してください。 さらに、開発者は値を特定の列挙値に変換できる逆シリアル化メソッドを提供する必要があることに注意してください。
class PhoneyEnumByValue(Enum): TheWanderer = 'The Wanderer' Mentiroso = 'Mentiroso' FakeBrenda = 'Faker Extraordinaire' NotSet = 'Not Set' @classmethod def deSerialize(cls, value: str) -> 'PhoneyEnumByValue': @classmethod def deSerialize(cls, value: str) -> 'PhoneyEnumByValue': match value: case PhoneyEnumByValue.TheWanderer.value: phoneyEnum: PhoneyEnumByValue = PhoneyEnumByValue.TheWanderer case PhoneyEnumByValue.Mentiroso.value: phoneyEnum = PhoneyEnumByValue.Mentiroso case PhoneyEnumByValue.FakeBrenda.value: phoneyEnum = PhoneyEnumByValue.FakeBrenda case _: raise Exception('Unknown PhoneyEnumByValue') return phoneyEnum class ImpostorEnumByName(Enum): Low = 0.1 Medium = 0.5 High = 1.0 NotSet = -1.0
プロパティへのアクセスと変更はバージョン 1 とまったく同じです。
@property @configurationGetter(sectionName='General') def debug(self) -> str: return '' # never executed @debug.setter @configurationSetter(sectionName='General') def debug(self, newValue: str): pass
上記のスニペットは次の出力を生成します。
@property @configurationGetter(sectionName='Database', deserializeFunction=int) def dbPort(self) -> int: return -1 @dbPort.setter @configurationSetter(sectionName='Database',) def dbPort(self, newValue: int): pass
この記事のソースコードはここにあります。 サポート クラス SingletonV3 を参照してください。 ConfigurationProperties
の実装を参照してください。実装の結果は、コードの消費者として満足しました。 型付きプロパティを取得および設定することができました。 当初期待していたほど多くのコードは削除されませんでした。 ただし、再利用可能なコードは提供されました。 ただし、個々のプロパティを生成する必要があるため、PyCharm で ライブ テンプレート を作成するように求められました。
次の投稿では、いわゆる動的プロパティを実装しました。 すべての定型コードを完全に削除し、前述の利点を維持しました。
以上が楽な Python 設定ファイル バージョン 2 に向けての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。