Checking types from an optional module

30 Views Asked by At

Say I have to check the type of an object before doing something to it. The objects have different APIs so they need to get dispatched to their own function (I can't simply rely on duck typing). Additionally, the objects could be from one of multiple optionally imported modules. In order to check the type with isinstance, I need to load the module first.

What's the best pattern for doing this?

For example, consider the following, where the modules may not be loaded (or exist in the environment).

if isinstance(obj, module1.class1):
    return fcn1(obj)
elif isinstance(obj, (module2.class2a, module2.sub1.class2b)):
    return fcn2(obj)
elif isinstance(obj, module3.class3):
    return fcn3(obj)

Here's my messy solution that tries to load all modules at the beginning (not on-demand):

import operator
import importlib

# List of (module_name, list(classes in module), function to call)
module_functions = [
    ('module1', ['class1'], fcn1), 
    ('module2', ['class2a', 'sub1.class2'], fcn2),
    ('module3', ['class3'], fcn3),
 ]

function_dispatch = {}
for module_name,class_names,fcn in module_functions:
    try:
        module = importlib.import_module(module_name)
        classes = tuple([operator.attrgetter(c)(module) for c in class_names])
        function_dispatch[classes] = fcn
    except:
        pass

def run_function(obj):
    for classes,fcn in function_dispatch.items():
        if isinstance(obj, classes):
            return fcn(obj)
    else:
        raise KeyError('No function for object')

run_function(module1.class1())
run_function(module2.sub1.class2b())
run_function(list())  # Exception

Is there a more elegant/clean/simple way to do this? Or even a way to try importing the modules on-the-fly instead of all at the beginning?

0

There are 0 best solutions below