4 ms·
The article really has something against map and filter. Specifically: squares_under_10 = filter(lambda x: x < 10, map(lambda x: x*x, numbers)) squares_
by BrandonM 18y ago
The article really has something against map and filter. Specifically:
squares_under_10 = filter(lambda x: x < 10, map(lambda x: x*x, numbers))
squares_under_10 = [number*number for number in numbers if number*number < 10]
Those two lines are functionally different; the second one (the one the article prefers) performs a costly multiplication twice.
I'm not saying list comprehensions are bad... I use them a ton. I just acknowledge that there are times where map and filter make a lot of sense. Even for trivial reasons like wrapping lines, using map allows you to break at commas instead of embedding backslashes in your code and trying to decide how it should all align.
If you haven't, check out the itertools standard library module. The power held in these functional, generator-based functions is amazing. Since I started using it, I don't know how many times I've used:
imap(func, izip(somelist, repeat(somevalue)))
and other such paradigms.
Hmm... more problems with the article:
numbers = [1,10,100,1000,10000]
if [number for number in numbers if number < 10]:
print 'Success'
# Output: 'Success!'
This is terrible. It may look nice all on one line, but it goes through the whole list when it doesn't need to. Better is:
for number in numbers:
if number < 10:
print "Success"
break
A problem with using the and ... or paradigm:
result = test and 'Test is True' or 'Test is False'
The page mentions that "Test is True" must evaluate to True or else it will always be skipped over even if test evaluates to True. It fails to mention, however that "Test is False" must also evaluate to True. Otherwise, if test evaluates to False, the entire expression returns False. Thus
s = foo and "word: "+foo or ""
will assign False to s instead of the desired "". In this case, it is quite clear that
s = "word: "+foo if foo else ""
is preferable.
I didn't find the article all that helpful, personally. It puts forward inefficient solutions as the recommended methods, and it doesn't offer much that I didn't already know. The two things that I learned, which I'm not sure that I'll ever use, are function decorators and the "string in substring" syntax.
- scott_s 18y agoPreferring the lambda expression because the list comprehensive performs a multiplication operation twice is, I think, misguided. The multiplication probably isn't that expensive compared to the rest of the code.
- yourmomis1337 18y agoYou're right about the map function, it is slightly more efficient in this case. But if you're multiplying 2 numbers together 10 times instead of 5, is it really significantly more efficient to use map? I suppose map/filter vs. list comprehensions/generator functions is really a matter of personal taste. And not to start a flame war, but the code: numbers = [1,10,100,1000,10000] if [number for number in numbers if number < 10]: print 'Success' # Output: 'Success!' actually does say that it's less efficient... granted it's buried in a paragraph so it's maybe not too obvious ; )... if you're using Genshi or something similar though you need to be able to toss crazy things in one line sometimes. And 'Test is False' doesn't have to evaluate to True... if it is false, it is still the value returned by the entire expression. Not the actual value 'False'. I actually disagree with your example s = foo and "word: "+foo or "" I tried it and "" got assigned to s... And dude, the string in substring syntax is awesome!
- icey 18y agoThis is completely unrelated, but why do some comments render at a lighter shade of gray than other comments? This comment renders at #323232, and the rest of them render at #000
- jcl 18y agoComments with 1 point or fewer are rendered in progressively grayer text, presumably to make them easier to filter out visually.
- BrandonM 18y agoYou're right about the map function, it is slightly more efficient in this case. But if you're multiplying 2 numbers together 10 times instead of 5, is it really significantly more efficient to use map? I suppose map/filter vs. list comprehensions/generator functions is really a matter of personal taste. I don't understand what you mean here. No matter how many numbers you're multiplying, the result is that you're doing twice as many as necessary. Now, with list comprehensions (and a generator for efficiency), it could have been written squares_under_10 = [sq for sq in (n*n for n in numbers) if sq < 10] That is the best of both worlds if you are against the use of map and filter. And 'Test is False' doesn't have to evaluate to True... if it is false, it is still the value returned by the entire expression. Not the actual value 'False'. I actually disagree with your example Hmm... very strange, you are absolutely right. I'm almost positive I've been bitten by a bug related to and... or before. It must have been something else, although I'm sure it wasn't the case where the "Test is True" value evaluated to False. Very weird... And dude, the string in substring syntax is awesome! I admit that is awesome, I just couldn't remember the last time I'd used index or find, anyways. I'll certainly be using it the next time the opportunity presents itself, though.
- nostrademons 18y ago"using map allows you to break at commas instead of embedding backslashes in your code" I usually break list comprehensions before the 'for', and then again before the 'if' if they still need it. No backslashes. Implicit line continuation works as well within list comprehensions as it does in function calls. "if [number for number in numbers if number < 10]:" I would've used: if any(number < 10 for number in numbers): Or alternatively if any(itertools.imap(lambda x: x < 10, numbers)): 'any' short circuits its evaluation if it finds a true item , and the generator expression doesn't need to be evaluated fully. (I think the first is more readable.) I also didn't find all that much that was new and interesting in the article, but that's because I went hunting for articles like this when I first started getting into Python seriously, and have been programming full-time in it for 8 months now.
- llimllib 18y agoThis is where haskell makes me jealous if any (< 10) numbers is so much prettier. I really want a dynamic language with haskell's beautiful function composition.
- BrandonM 18y agoI usually break list comprehensions before the 'for', and then again before the 'if' if they still need it. No backslashes. Implicit line continuation works as well within list comprehensions as it does in function calls. Wow, I learned more from this comment than I did from the entire wiki page. I wonder why I never realized this before... I tend to break my list comprehensions the same way, and for some reason I thought the backslashes were necessary. if any(number < 10 for number in numbers): Very nice. I need to start using some of these builtins a little more. In particular, I'm pretty sure that I've used for foo, index in izip(list, count()) before instead of simply using enumerate. any is one that I'll definitely have to keep in mind.
- globalrev 18y agoexcept it is not working? >>> numbers = [1,10,100,1000,10000,100000,1000000] >>> if any(number < 10 for number in numbers):print number Traceback (most recent call last): File "<pyshell#4>", line 1, in <module> if any(number < 10 for number in numbers):print number NameError: name 'number' is not defined >>> if any(number < 10 for number in numbers): print number Traceback (most recent call last): File "<pyshell#7>", line 2, in <module> print number NameError: name 'number' is not defined >>>