I want to check if some line ends with any substring defined in some list. Is there a better way than following one?
endsA = ['foo', 'bar', 'fur', 'beer']
endsB = ['door', ... ]
def checkEnds(line, ends):
for end in ends:
if line.endswith(end):
return True
....
if checkEnds(line, endsA):
do_something()
2 Answers 2
Yes, there is! Generator comprehensions and the any
function to the rescue.
def checkEnds(line, ends):
return any(line.endswith(end) for end in ends)
Just like the original code, this only checks as many line.endswith(end)
as necessary, returning True
on the first True
result.
-
\$\begingroup\$ Thank you (+1). I am wondering will
endsWith
perform to each element ofends
or till firstTrue
? \$\endgroup\$Loom– Loom2016年03月30日 15:40:34 +00:00Commented Mar 30, 2016 at 15:40 -
2\$\begingroup\$ Written in this form, it will stop as soon as possible. \$\endgroup\$Sjoerd Job Postmus– Sjoerd Job Postmus2016年03月30日 16:13:01 +00:00Commented Mar 30, 2016 at 16:13
-
1\$\begingroup\$ @SjoerdJobPostmus: That would be a good detail to have as a note in your answer, IMO. +1 \$\endgroup\$Zach Gates– Zach Gates2016年03月30日 21:52:28 +00:00Commented Mar 30, 2016 at 21:52
-
\$\begingroup\$ @ZachGates: Added it to the answer instead. \$\endgroup\$Sjoerd Job Postmus– Sjoerd Job Postmus2016年03月31日 07:48:58 +00:00Commented Mar 31, 2016 at 7:48
@Sjoerd's solution using any()
is definitely the way to go.
I'd also like to point out a recommendation in PEP 8:
- Be consistent in return statements. Either all return statements in a function should return an expression, or none of them should. If any return statement returns an expression, any return statements where no value is returned should explicitly state this as
return None
, and an explicit return statement should be present at the end of the function (if reachable).
In your case, this means that if you were to keep your for
loop, you should also write an explicit return False
instead of returning None
by falling off the end of the function.
I would also suggest a better name for your function: any_suffix_matches(suffixes, string)
. This name leads to more readable code in the caller, and clearly conveys the idea that the function is a true-false test. It also conforms to the PEP 8 naming convention.
if any_suffix_matches(endsA, line):
do_something()
Note that I've also swapped the order of the parameters. Since "contains any of these suffixes" is the test, and the test is applied to some string, the suffixes should be placed closer to the function name. You see this design convention in re.search(pattern, string)
, for example.