How should I write this string-prefix check so that it's idiomatic Python?
I have a couple of lists of items:
specials = ['apple', 'banana', 'cherry', ...]
smoothies = ['banana-apple', 'mocha mango', ...]
I want to make a new list, special_smoothies
, consisting of elements in smoothies
that start with the elements in specials
. However, if specials
is blank, special_smoothies
should be identical to smoothies
.
What's the most Pythonic way to do this? Is there a way to do this without a separate cond开发者_如何学JAVAitional check on whether specials
is blank?
Since you want the behavior for empty specials to be different from the natural limit of the behavior for non-empty, you do need to special-case:
if specials:
specialsmoothies = [x for x in smoothies
if any(x.startswith(y) for y in specials)]
else:
specialsmoothies = list(smoothies)
In other words, you want the behavior for empty specials to be "all smoothies are specials", while the natural limit behavior would be to say that in that case "no smoothie is special" since none of them starts with one of the prefixes in specials (since there are no such prefixes in that case). So, one way or another (an if/else or otherwise) you do need to make a special case in your code to match the special, irregular case you want in its semantics.
There are a couple of ways to do it without an explicit check on specials
. But don't do them.
if specials:
special_smoothies = [x for x in smoothies if any(True for y in specials if x.startswith(y))]
else:
special_smoothies = smoothies[:]
str.startswith()
accepts tuple as an argument:
if specials:
specialsmoothies = [x for x in smoothies if x.startswith(tuple(specials))]
else:
specialsmoothies = list(smoothies)
Why complicate things? I think this is the most readable. Alex and Ignacio both give good reasons for not avoiding the else
clause.
special_smoothies = []
if specials:
for smoothy in smoothies:
for special in specials:
if smoothy.startswith(special):
special_smoothies.append(smoothy)
else:
special_smoothies = smoothies[:]
精彩评论