Как динамически знать и создавать только один класс, реализованный в модуле Python - PullRequest
2 голосов
/ 28 апреля 2020

Предположим, что в. В "./datawriters/generic_data_writer.py" у меня есть:

import os

class GenericDataWriter:
   def __init__(self, config):
       self.output_folder = config.get('output_folder')
       self.output_file_name = config.get('output_file')
       self.output_file_path_and_name = os.path.join(self.output_folder, self.output_file_name)
       self.index = config.get('include_index') # whether to include index column from Pandas' dataframe in the output file

Предположим, у меня есть JSON файл конфигурации, который имеет пару ключ-значение, например:

{
"__comment__": "Here, user can provide the path and python file name of the custom data writer module she wants to use."
"custom_data_writer_module": "./data_writers/excel_data_writer.py"

"there_are_more_key_value_pairs_in_this_JSON_config_file": "for other input parameters"
}

В "main.py" я хочу импортировать модуль записи данных на основе custom_data_writer_module, предоставленного в файле конфигурации JSON выше. Итак, я написал это:

import os
import importlib

def main():
    # Do other things to read and process data

    data_writer_class_file = config.get('custom_data_writer_module')
    data_writer_module = importlib.import_module\
            (os.path.splitext(os.path.split(data_writer_class_file)[1])[0])

    dw = data_writer_module.what_should_this_be?   # <=== Here, what should I do to instantiate the right specific data writer (Excel or CSV) class instance?
    for df in dataframes_to_write_to_output_file:
        dw.write_data(df)

if __name__ == "__main__":
    main()

Как я и просил в коде выше, я хочу знать, есть ли способ получить и создать экземпляр класса, определенного в модуле Python, предполагая, что существует ТОЛЬКО ОДИН класс определено в модуле. Или, если есть лучший способ реорганизовать мой код (используя какой-то шаблон) без изменения структуры конфигурационного файла JSON, описанного выше, я бы хотел узнать у Python экспертов по StackOverflow. Заранее благодарю за ваши предложения!

1 Ответ

2 голосов
/ 28 апреля 2020

Вы можете сделать это легко с помощью vars:

cls1,=[v for k,v in vars(data_writer_module).items()
       if isinstance(v,type)]
dw=cls1(config)

Запятая заставляет обнаруживать ровно один класс. Если модулю разрешено делать что-то вроде from collections import deque (или даже foo=str), вам может потребоваться фильтрация на основе v.__module__.

...