首页 > 解决方案 > 如何动态地知道和实例化在 Python 模块中实现的一个类

问题描述

假设在“./data_writers/excel_data_writer.py”中,我有:

from generic_data_writer import GenericDataWriter

class ExcelDataWriter(GenericDataWriter):
   def __init__(self, config):
       super().__init__(config)
       self.sheet_name = config.get('sheetname')

   def write_data(self, pandas_dataframe):
       pandas_dataframe.to_excel(
           self.get_output_file_path_and_name(), # implemented in GenericDataWriter
           sheet_name=self.sheet_name,
           index=self.index)

在“./data_writers/csv_data_writer.py”中,我有:

from generic_data_writer import GenericDataWriter

class CSVDataWriter(GenericDataWriter):
   def __init__(self, config):
       super().__init__(config)
       self.delimiter = config.get('delimiter')
       self.encoding = config.get('encoding')

   def write_data(self, pandas_dataframe):
       pandas_dataframe.to_csv(
           self.get_output_file_path_and_name(), # implemented in GenericDataWriter
           sep=self.delimiter,
           encoding=self.encoding,
           index=self.index)

在“./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 配置文件的结构,我想向 StackOverflow 上的 Python 专家学习。提前感谢您的建议!

标签: pythonpython-3.xooppython-importlib

解决方案


您可以通过以下方式轻松做到这一点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__.


推荐阅读