3 ms·
There's always been multiple ways to do something in Python, just one best way, and the best way has been known to change between versions. See: list comprehen
by amyjess 10y ago
There's always been multiple ways to do something in Python, just one best way, and the best way has been known to change between versions.
See: list comprehensions obsoleting most uses of map() and filter(), then generator expressions obsoleting any uses of list comprehensions that don't need a list object
Here's four ways to do the same thing.
Naïve way:
foo = []
for x in bar:
if meets_some_condition(x):
foo.append(transform(x))
do_something_with(foo)
With map/filter:
do_something_with(map(transform, filter(meets_some_condition, bar)))
With list comprehensions:
do_something_with([transform(x) for x in bar if meets_some_condition(x)])
With generator expressions:
do_something_with(transform(x) for x in bar if meets_some_condition(x))
All four of those are valid in modern Python, but the latter and only the latter is the right way to do it.
Before Python 2.0, either map/filter or the naïve way was the right way (TBH, I'm not familiar with what was considered right in the old days). When Python 2.0 came out, list comprehensions became the right way. When Python 2.4 came out, generator expressions became the right way. The right way depends on your version of Python.
Or for that matter, look at old-style classes vs. new-style classes. When new-style classes came out, they immediately became the one and only right way to do classes, but old style classes still stuck around for the rest of the 2.x series.
- cookiecaper 10y agoI'm going to disagree with you there and prefer the "naive way". This is the clear and explicit way to express your intent. Personally, I'm a big fan of a few more lines for more clarity (within reason), and not a fan of unique, language-specific incantations like comprehensions just for the sake of syntactic sugar. An implicit coding style that requires the reader to look up the semantics of Python's comprehensions (and also makes it harder to unwind/inject debugging/keep line lengths reasonable) is a negative unless you're gaining something besides brevity. I understand some claim that comprehensions are faster for various reasons, but this is presumably implementation dependent and shouldn't be assumed unless you know it's the case in your implementation. I also understand that the generator expression uses less memory, but the generator version can be written the long way too: def test_bar(bar): for foo in bar: if meets_some_condition(foo): yield transform(foo) do_something_with(test_bar(bar)) I know that Python is pretty reasonable but I don't like starting the descent down into the alphabet-soup madness that we get in a lot of other languages.
- ghshephard 10y agoBut List comprehensions, and now generators, are what python, "Pythonic". I'm a relative novice with python, but they are straightforward to understand, and are fairly consistently used by practitioners of the language. But, I agree with you regarding creeping complexity in general - @wrappers/decorators confused me for the longest time, and I often wonder how someone not familiar with the language is supposed to understand what they are doing.
- dragonwriter 10y ago> This is the clear and explicit way to express your intent. I disagree. For the (common) circumstances where genexp's are appropriate, they are also the most clear and explicit way of expressing intent (explicit loops express the mechanism, not the intent.) For cases where you need a list object, list comprehension are the most direct expression of intent. There's cases where explicit looping is the most clear expression of intent; usually, this would be where complex logic is needed within each loop iteration.