I want to perform some dynamic type checking for the inputs and outputs of a method. The solution that I've came up with is as follows. Basically, in the __init__
function of the superclass, I update the subclass method with some dynamic type checking for both input and output. Note that, the type-checking should be based on the attributes (AlgorithmAttribute
) that user defined during instantiation. I wonder if there is any better solution out there.
import abc
import six
import attr
from typing import Dict, Text
@attr.s
class AlgorithmAttribute(object):
inputs = attr.ib(type=Dict[Text, int])
outputs = attr.ib(type=Dict[Text, int])
class BaseHandler(six.with_metaclass(abc.ABCMeta, object)):
def __init__(self, alg):
self.alg = alg
self.out = self.__getattribute__('prepare')
self.__setattr__('prepare', self.temp)
def temp(self, a, b):
result = self.out(a, b)
# Verifies inputs.
if set(a.keys()) == set(self.alg.inputs.keys()):
print('Inputs correct!')
# Verifies outputs.
if set(result.keys()) == set(self.alg.outputs.keys()):
print('Outputs correct!')
return result
@abc.abstractmethod
def prepare(self, a):
pass
class SubHandler(BaseHandler):
def __init__(self, alg):
super(SubHandler, self).__init__(alg)
def prepare(self, a:Dict[Text, int], b:Dict[Text, int]) -> Dict[Text, int]:
return {'c': 33}
alg = AlgorithmAttribute(inputs={'a': 2, 'b': 3}, outputs={'c': 10})
sh = SubHandler(alg)
sh.prepare({'a': 20, 'b': 200}, b={'c': 20, 'd': 200})
It's not very clear to me why you validate the first argument of prepare()
against inputs
or what's the point of passing a dict with unused values to AlgorithmAttribute
, but a more Pythonic way, in my opinion, would be to ditch the classes and use a decorator:
from dataclasses import dataclass
from typing import Dict, Text
@dataclass
class AlgorithmAttribute(object):
inputs: Dict[Text, int]
outputs: Dict[Text, int]
def validate_inputs_outputs(validation_params: AlgorithmAttribute):
def wrap(func):
def wrapped_func(*args, **kwargs):
result = func(*args, **kwargs)
# Verifies inputs.
if set(args[0].keys()) == set(validation_params.inputs.keys()):
print('Inputs correct!')
# Verifies outputs.
if set(result.keys()) == set(validation_params.outputs.keys()):
print('Outputs correct!')
return result
return wrapped_func
return wrap
@validate_inputs_outputs(AlgorithmAttribute(inputs={'a': 2, 'b': 3}, outputs={'c': 10}))
def prepare(a:Dict[Text, int], b:Dict[Text, int]) -> Dict[Text, int]:
return {'c': 33}
prepare({'a': 20, 'b': 200}, b={'c': 20, 'd': 200})