简体   繁体   English

如何动态地知道和实例化在 Python 模块中实现的一个 class

[英]How to know and instantiate only one class implemented in a Python module dynamically

Suppose in "./data_writers/excel_data_writer.py", I have:假设在“./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)

In "./data_writers/csv_data_writer.py", I have:在“./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)

In "./datawriters/generic_data_writer.py", I have:在“./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

Suppose I have a JSON config file that has a key-value pair like this:假设我有一个 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"
}

In "main.py", I want to import the data writer module based on the custom_data_writer_module provided in the JSON config file above.在“main.py”中,我想根据上面 JSON 配置文件中提供的custom_data_writer_module导入数据写入器模块。 So I wrote this:所以我写了这个:

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()

As I asked in the code above, I want to know if there's a way to retrieve and instantiate the class defined in a Python module assuming that there is ONLY ONE class defined in the module.正如我在上面的代码中询问的那样,我想知道是否有一种方法可以检索和实例化 Python 模块中定义的 class 假设在定义的模块中只有一个 ZA2F2ED4F8EBC2CBB4C21A29DC40AB61 模块。 Or if there is a better way to refactor my code (using some sort of pattern) without changing the structure of JSON config file described above, I'd like to learn from Python experts on StackOverflow.或者,如果有更好的方法来重构我的代码(使用某种模式)而不改变上述 JSON 配置文件的结构,我想向 StackOverflow 上的 Python 专家学习。 Thank you in advance for your suggestions!提前感谢您的建议!

You can do this easily with vars :您可以使用vars轻松做到这一点:

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

The comma enforces that exactly one class is found.逗号强制找到一个 class。 If the module is allowed to do anything like from collections import deque (or even foo=str ), you might need to filter based on v.__module__ .如果允许模块执行类似from collections import deque (甚至foo=str )的操作,您可能需要基于v.__module__进行过滤。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM