Ini adalah artikel terakhir dalam siri ini. Pelaksanaan ini bertujuan untuk memperbaiki kelemahan utama kod plat dandang yang saya terangkan dalam artikel sebelumnya. Saya memanggil pelaksanaan ini kelas sifat dinamik.
Rajah kelas berikut menunjukkan kelas boleh guna semula DynamicConfiguration dan struktur data sokongan yang diperlukan untuk pembangun menggunakan fungsi ini. Ia masih menyediakan semua fungsi asas versi 2 termasuk pengikat but auto, penciptaan bahagian yang hilang dan nilai utama.
Saya akan membentangkan kod sumber penuh untuk aplikasi yang ingin menggunakan kelas ini. Saya menggunakan sifat-sifat terdahulu yang telah kita bincangkan dalam 3 artikel sebelum ini.
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)
Baris 45-50 ialah kod yang perlu anda tulis. Pada asasnya, anda hanya memastikan bahawa anda lulus nama fail, nama modul dan bahagian konfigurasi. Jenis Bahagian ini berasal daripada modul DynamicConfiguration.
Baris 21-28 dan 30-36 ialah kamus ValueDescriptions. KeyName ialah harta dan menunjuk ke ValueDescription. Perhatikan bahawa penunjuk tentang cara untuk mengekalkan penghitungan dialihkan daripada penghias pelaksanaan sebelumnya kepada atribut boolean dalam ValueDescription.
Jika anda melihat dengan teliti pada rajah kelas untuk DynamicConfiguration anda akan melihat bahawa ia melaksanakan dua kaedah sihir Python. Mereka ialah kaedah __getattr__(diri, nama)__ dan __setattr__(diri, nama, nilai)__.
Berikut ialah kod untuk __getattr__. Ini kelihatan sangat mirip dengan penghias yang kami gunakan dalam versi 2. Kerja utama berlaku pada panggilan pada talian 14 kepada kaedah yang dilindungi _lookupKey(). Ia mengembalikan huraian penuh atribut supaya kita boleh mensimulasikan pengambilan semula atribut.
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
Berikut ialah pelaksanaan__setattr__(). Perhatikan sokongan untuk penghitungan dalam baris 22-27 dan ciri tulis lalu dalam baris 30.
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()
Mengakses dan mengubah suai sifat adalah sama seperti dalam versi 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=}')
Coretan di atas menghasilkan output berikut.
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'
Kod sumber untuk artikel ini ada di sini. Lihat kelas sokongan SingletonV3. Lihat pelaksanaan
Atas ialah kandungan terperinci Ke Arah Fail Konfigurasi Python yang Mudah Versi 3. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!