4 ms·
It seems to me if you want to write code like this, you shouldn't write it in Python. Python has much simpler, built-in ways to do most of the things he's sugge
by benhoyt 14y ago
It seems to me if you want to write code like this, you shouldn't write it in Python. Python has much simpler, built-in ways to do most of the things he's suggesting. For instance, he says "good" for this code:
reduce(operator.add, map(len, ss))
No! The simpler (and more efficient, as it doesn't have to build a list of results!) way to do that is using the built-in sum() with a generator expression:
sum(len(s) for s in ss)
The rest of the slides are full of similarly-complex idioms. Another one:
def square_sum(a, b):
return sum(map(lambda x: x**2, range(a, b+1)))
Please, no! Generator expressions are there for a reason. Much simpler and much more efficient would be:
def square_sum(a, b):
return sum(x**2 for x in range(a, b+1))
In fact, most places you see map() in Python can be rewritten as generator expressions.
For stuff like functools.partial, in simple cases, isn't it clearer to just write this?
def debug(message):
log('debug', message)
I like his use of operator.itemgetter/operator.methodcaller, though. They're useful for sort keys and stuff, and faster and often clearer than lambdas.
Also: namedtuple is great instead of "using classes as attribute containers".
- babarock 14y agoI may be going out on a limb here, but I don't think he's actually suggesting using `reduce(operator.add, ...)` instead of `sum()`. He argues himself a few slides later that short functions are always better than long ones. If you look at the title of the slides, I think he's simply presenting what FP is: a chain of maps, filters and folds. It's true that Python will use a list comprehension or a generator expression where you would normally do this, but Python 3 still includes map() and filter(). (Despite Guido not being a big fan of these functions - http://www.artima.com/weblogs/viewpost.jsp?thread=98196 http://www.artima.com/weblogs/viewpost.jsp?thread=98196). My point is simply that the presentation does a good job at exposing what FP is and how to implement it in Python. Moving from maps to comprehensions comes naturally, once you get the hang of the idea. PS: I have the same question about functools.partial. Can somebody answer this?
- atdt 14y ago> ...faster and often clearer than lambdas. $ python -m timeit 'import string;from operator import itemgetter;[itemgetter('slice') for x in string.letters]' 100000 loops, best of 3: 14.2 usec per loop $ python -m timeit 'import string;from operator import itemgetter;[lambda x: x.slice for x in string.letters]' 100000 loops, best of 3: 10.4 usec per loop > Also: namedtuple is great instead of "using classes as attribute containers". Er, OK. Just don't look at the implementation[1]. Cannot be unseen. [1]: http://hg.python.org/cpython/file/2.7/Lib/collections.py#l233 http://hg.python.org/cpython/file/2.7/Lib/collections.py#l23...
- bvdbijl 14y agoMy eyes... So a named tuple is just a class, nothing special about it really
- andreasvc 14y agoYou're measuring the wrong thing. itemgetter() is supposed to be called just once and it's the returned function that is used in the loop/map. It should be: python -m timeit 'import string;from operator import itemgetter; getter=itemgetter('slice'); [getter(x) for x in string.letters]'
- benhoyt 14y agoTrue. But you should also put the setup in a -s option, because you're not timing the imports. And you don't really need the loop, because timeit does a bunch of loops for you: >python -m timeit -s "from operator import itemgetter; elem0 = itemgetter(0)" "elem0('s')" 10000000 loops, best of 3: 0.095 usec per loop >python -m timeit -s "from operator import itemgetter; elem0 = lambda x: x[0]" "elem0('s')" 10000000 loops, best of 3: 0.138 usec per loop
- kachayev 14y agoThis example was given to describe map/reduce pattern, not advice to use it instead of sum: reduce(operator.add, map(len, ss)) You know, it's hard to understand new concept. And it's twice harder to explain new concept with sophisticated code examples. So I used as simple code and situations as possible. The same for square_sum - it's easier "to see" functional pattern in map(f,l) than in (f(x) for x in l). Regarding to debug function and partial function application, - it depends. As for me debug = partial(log, "debug") is easier and meaningfully describe what's actually going on. But here we have only one function, what if you have to create 5-6 same functions? Would you prefer "def" syntax instead of partial? I have one more example of using this pattern in more sophisticated situation - code listing for dictionary binding to list of functions, "partial" looks really naturally.