Often when I'm writing a set of utility functions, I find myself wanting a function that applies some logic to multiple items, as well as a function that does the same with just a single item. There are a lot of potential solutions to this, but I always find myself flipping back and forth.
- I could write an exclusively singular version of the function (
modify_item(item)
) and usemap
, comprehension, or a foreach externally. I don't want to do this every danged time I call it with multiple items though. - I could write an exclusively explicitly plural version of the function (
modify_items(items)
) that does the iteration inside. But I don't want to call it with a list every time either. Better than always singular, but still awkward to call. This would also support bulk operations better. - I could write an agnostic function that checks the input's type (
modify_item(item)
). If it's not iterable, it'll wrap it in a list and then iterate. This seems to be the best option, but the lure of star operators always gets me... - I could write an agnostic function that takes a variable number of inputs (modify_item(*items)) and iterates over them. This gives me a good calling syntax and automatically packs the items into an iterable for me. The problem I always run into here is that adding subsequent arguments or keyword arguments is awkward.
- Finally, I could just throw up my hands and write a plural function as above, and a singular one that would wrap the parameter in a list and pass it to the plural one. Then I'd have to write double the functions, which is silly.
It seems like javascript libraries usually do the type checking option (#3), and that's the one I like best. In that case, you have the question of naming conventions. I think I favor singular, but I'm not sure about that.
Examples are in python, but this question could be applied to most languages.
-
2You can generally ask on Meta Stack Exchange about where to post about a question if you're unsure.SuperBiasedMan– SuperBiasedMan2015年09月08日 18:12:06 +00:00Commented Sep 8, 2015 at 18:12
2 Answers 2
In these instances, I usually make two versions of the function, with the multiple version simply calling the singular version, something like this:
class Foo:
def transform_entity(bar):
return do_things(bar)
def transform_entities(bars):
return [transform_entity(b) for b in bars]
It's pretty self-explanatory, avoids any explicit wrapping, and allows you to use arguments properly without manual wrapping (unlike trying to do something terrible with varargs).
A friend of mine convinced me of option number three, with the addition that he uses a helper function called ensure_plural
to ensure that the input is plural before continuing. This keeps it nice and declarative. The helper function could take a few different forms:
- As a decorator, it would just modify the inputs before even getting to the main function. The problem is that it would have to assume some stuff.
- It could just be called on the value that needs to be plural when necessary.
- I've also come up with a version called
if_plural
, which would take a value and a function and return the result of applying the function directly to the value if singular, or of mapping the function over the value if plural.