AlexLordThorsen
AlexLordThorsen

Reputation: 8498

Looping through imported classes in python

For a multitude of reasons I find myself in the position of importing many python modules and wanting to iterate through each of the Classes in the module.

from capacity_hdd_parser import CapacityHDDParser
from capacity_ssd_parser import CapacitySSDParser
from checksum_parser import ChecksumParser
.
.
.

each parser inheritances from a base class and has a method I want to call on each parser

parsers = [CapacityHDDParser, CapacitySSDParser, ChecksumParser]
for parser in parsers:
    parser_instance = parser()
    data_returned = parser_instance.parse(logset_path)
    # Do a bunch of post processing here.

My problem is that I have many parsers to go through and I feel like there has to be a way to dynamically iterate through imported class. Having to hand write each of these is not only a pain in the ass it makes the intent of my code much harder to see in the noise.

Upvotes: 3

Views: 2359

Answers (3)

Silas Ray
Silas Ray

Reputation: 26160

If you don't need them in the global namespace, you could use importlib.import_module.

from importlib import import_module

for module_name, class_name in (('capacity_hdd_parser', 'CapacityHDDParser'),
                                ('capacity_ssd_parser', 'CapacitySSDParser'),
                                ('checksum_parser', 'ChecksumParser')):
    data_returned = getattr(import_module(module_name), class_name)().parse(logset_path)
    # Other processing here

You might also want to consider consolidating your parser classes in to a single package. It would make this approach more DRY, and also probably be more Pythonic. One class per file is usually overly redundant/verbose in Python.

Upvotes: 4

Paulo Scardine
Paulo Scardine

Reputation: 77369

Kids, do not try to this at home:

parsers = [v for (k, v) in locals().items() 
             if k.endswith('Parser')]

You may make it a little bit safer with a better test condition.

[update]

The declarative approach by Silas is the safe bet:

PARSERS = {
    'capacity_hdd_parser': 'CapacityHDDParser',
    'capacity_ssd_parser': 'CapacitySSDParser',
    'checksum_parser': 'ChecksumParser',
    ...
}

def load_parser(module, parser):
    return getattr(importlib.import_module(module), parser)

parsers = [load_parser(*item) for item in PARSERS.items()]

Better yet, you can replace the PARSERS dict with a config file.

Upvotes: 3

jfs
jfs

Reputation: 414795

for Parser in get_registered_parsers():
    data = Parser().parse(logset_path)

Define get_registered_parsers() by any means necessary including black magic e.g., setuptools entry_points, or yapsy (plugin architecture), or ABCs (explicit register() function), etc.

Upvotes: 0

Related Questions