When coding in Python, I often see this pattern:
filename = [f for f in file_list if ....]
The above expression traverses through the whole list to find items that fit the criteria (the if phrase), then return the first item.
This construction is inefficient because it did not stop even after it found the first item. The effect is more obvious if one or more of these conditions happen:
- The list is long
- The criteria is time consuming
- This construction happens several times
A better, more efficient approach is to stop searching once you found your candidate:
filename = next(f for f in file_list if ...)
In this approach, the expression inside the
next function is a generator expression which returns a generator object. The next function returns the first item that fits the criteria. The net effect is the code does not traverse the entire list. Instead, it stops right after locating the first item.
Note that both approaches do not guard against such cases as empty list for
file_list, or when the search came up empty.
Likewise, to find the last item, instead of:
filename = [f for f in file_list if ....][-1]
filename = next(f for f in reversed(file_list) if ...)
reversed function requires its argument to be a sequence (list, tuple, …) and reverse itself returns a generator object. In this situation, we have nested generators, but the effect is the same: the code will stop once it found the last item that fits the criteria and not traversing the entire list.