I advice you to check input before trying to run something potentially mispelled, or absent. The input dict
may even contain args
and kwargs
as values in a tuple
like in the following example:
actions = dict(
walk=(tuple(), dict(steps=10, step_size=50)),
wink=((1, 2, 3), dict(a=0)),
invalid=tuple(),
absent=(tuple(), None),
)
Assuming the Person
be like:
class Person:
def walk(self, step_size=0, steps=0):
print(f'Walking: {steps} steps of size {step_size}')
def wink(self, x, y, z, a):
print(f'Wink with {x}, {y}, {z} and a {a}')
With the above Person
and the dict
built that way you can then write Bla
as follows:
class Bla:
availables = {'walk', 'wink', 'absent'}
def forbidden(self, *args, **kwargs):
print(f'{self.name}() is forbidden')
def __init__(self):
self.name = ''
def run(self, actions: dict):
p = Person()
for m, args in actions.items():
self.name = m
if len(args) != 2: continue
kwargs = args[1] or dict()
args = args[0] or tuple()
if m in Bla.availables:
method = getattr(p, m, self.forbidden)
try:
method(*args, **kwargs)
except (TypeError, ValueError, Exception) as e:
print(f'{str(e)} --> {self.name}({args}, {kwargs}')
Running that code you'll get:
Walking: 10 steps of size 50
Wink with 1, 2, 3 and a 0
absent() is forbidden
Hera are a couple of things worth mentioning:
The third argument to getattr
is the default value returned in case the given attr
is not present in the given object
.
By compiling Bla.availables
you can dinamically (i.e. changing during runtime) filter the members you want to be available for calling.
By using exception handling around the call to the method allows avoiding program crashes on wrong input to methods.
Having a dict
as input would not allow you to call the same method more than once on a given Person
object. If that is an issue for you I advice the use of tuples of tuples of tuples and dict
like ('wink'((1, 2, 3) dict(a=0)), ...)
.