I am writing a function of the form:
def fn(adict, b):
"""`adict` contains key(str): value(list). if `b` is a dict we have to
call `do_something` for pairs of lists from `adict` and `b` for
matching keys. if `b` is a list, we have to call `do_something`
for all lists in `adict` with `b` as the common second
argument.
"""
if isinstance(b, dict):
for key, value in adict.items():
do_something(value, b[key])
else:
for key, value in adict.items():
do_something(value, b)
def do_something(x, y):
"""x and y are lists"""
pass
I am aware that this may not be a good design (Is it bad design to base control flow/conditionals around an object's class?). But writing two functions, one taking b as a dict and another as a list, seems too redundant. What are some better alternatives?
There's indeed a pattern for such problems, it's named "multiple dispatch" or "multimethods". You can find a (quite simple) example Python implementation here http://www.artima.com/weblogs/viewpost.jsp?thread=101605
Using this solution, your code might look like:
from mm import multimethod
@multimethod(list, dict)
def itersources(sources, samples):
for key, value in sources.iteritems():
yield value, samples[key]
@multimethod(list, list)
def itersources(sources, samples):
for key, value in sources.iteritems():
yield value, samples
def fn(sources, samples):
for value1, value2 in itersources(sources, samples):
do_something_with(value1, value2)