I feel about list comprehensions the way I feel about regular expressions. Below a certain point of complexity, both are vastly superior ways of expressing what's going on. Above that point, comprehensibility drops off
fast, and they immediately become inferior tools.
For example, something like:
[some_func(y) for x, y in some_dict.items() if some_condition(x)]
...is, at least in my mind, eminently more readable than the imperative equivalent, and less PEBCAK-risky (i.e. what if you have to do two similar iterations and forget to use a different accumulator between the two?).
However, I totally agree with you re: "don't get too clever". Pretty much the instant you have nested comprehensions, or try to get clever iterating over multiple data structures in a single expression, it immediately becomes much worse than the imperative form, and you should feel a little bashful and bust out some loops, functions, and accumulators.
Same is true for regex. Something like:
($match) =~ qr/\A(?:foo|bar)[.]com (\d+)-baz$/
...while it does require you to know regex, is
way simpler and more robust than writing the equivalent stack of many string slicing conditions, and less error prone. However, once the "too clever" rubicon is crossed (subjective, but my personal rule of thumb is: more than 50chrs of non-literals or more than one lookaround expression), like list comprehensions, it rapidly becomes
much harder to understand than the equivalent long, explicit, string-slicing form.
As with many things, I think that skill in these areas is a matter of knowing when to stop.