0

If I have a list of objects that need to have an operation performed on each, is there a best practice in abstracting the loop or not?

  1. Looping over list and call

     def func(item):
         some_op(item)
         some_other_op(item)
    
     for item in items:
         func(item)
    
  2. Call method and loop internally

     def func(items):
         for item in items:
             some_op(item)
             some_other_op(item)
    
     func(items)
    

Iteration takes place in both, so I think it would come down to compiler settings because of all the calls to func. Other than reducing function calls, I think #2 allows for not re-writing the loop elsewhere if another method needs to call func; it can just pass a container of arbitrary size.

Is there any merit to one over the other?

2 Answers 2

5

Saving function call overhead is almost certainly a bad idea - unless you have profiled your program and know that the call is on your hot code path, you're going to waste much more time thinking about it than you can ever save.

Much more important is probably the question of code clarity and reuse. Alternative 2 commingles iterating with a complex operation on a specific data type. Unless you are absolutely, definitely sure that you will never, ever have to execute that operation on an individual data item rather than on a collection, best practice is to separate the two concerns and have func do only one thing. (And to give it a much better name, of course.)

2
  • So if methodA has a loop that calls func, and methodB has a loop that calls func, repeating the loop over a set of objects isn't duplicative (DRY-ish)? All names here are pseudo for ease. Future calls to a single item could be handled via func([item]) as well could it not?
    – pstatix
    Mar 15, 2021 at 17:17
  • "best practice is to separate the two concerns and have func do only one thing" - hm.. I wouldn't consider loops that big of a logic to separate it out just because of vague "best practices". Also refactoring the loop out of the method would be trivial should it be needed in the future. Mar 15, 2021 at 17:35
2

First of all, what you're writing in your examples are not methods but standalone functions. You can write them with any parameters of your choice, although the clarity arguments in Killian's answer still apply.

If you write methods, you need to consider which object is the receiver of the method call. It is absolutely natural to define a method on Item which performs the work on an individual item, but which object would be the recipient of a method that loops over the items? A specialized list subclass? Possible (afaik) but awkward in python. A container holding the list of items? Unless the container and its list have a specific purpose, this sounds like over engineering.

From an object oriented perspective it is most natural to define the functionality as a method on Item, and call it in a loop from the place where the list of items is handled. If there is an object holding that list then this object would be a good place for a method do_something_with_items(), but when the list only appears as a temporary intermediate data structure the loop would be just part of the code processing that data structure.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.