Posterous theme by Cory Watilo

python notes from reddit

 6 points7 points8 points 1 day ago

FWIW, here's a tricky Python function I wrote a while ago. It does a relatively simple operation that you see a lot in functional programming languages. What does it do?

def magic_function(*fs): return lambda x: reduce(lambda a,b: b(a), (fs+x)[::-1])

[–]null_ptr  3 points4 points5 points 1 day ago

It applies the functions in fs to the argument x, cumulatively. So magic_function(f1, f2)(z) will give f1(f2(z)).

Don't know much Python though, so please tell me if I'm wrong.

[–]drigz  0 points1 point2 points 5 hours ago

Almost - I think you need to pass a 1-item tuple to the result:

>>> magic_function(lambda x: x+3, lambda x: x*2)(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in <lambda> TypeError: can only concatenate tuple (not "int") to tuple >>> magic_function(lambda x: x+3, lambda x: x*2)((1,)) 5

This could be changed by replacing fs+x with fs+(x,).

[–]victusfate [S] -1 points0 points1 point 23 hours ago* 

I'm pretty new to python, but I'd like to go through and understand each step in your function.

the first line is a function definition which takes arbitrary arguments -had to look up the operator, woohoo learning

the second line starts with a declaration of lambda, which I assume is an inline temporary function. it looks like it is diveintpython

it takes an argument x, and returns a reduce function. I'm going out on a limb and guessing this reduce is something like the map/reduce from google and lisp and is some kinda cumulative function... reduce and other python builtin functions

reduce(function, iterable[, initializer])
Apply function of two arguments cumulatively to the items of iterable, from left to right, so as to reduce the iterable to a single value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates ((((1+2)+3)+4)+5). The left argument, x, is the accumulated value and the right argument, y, is the update value from the iterable. If the optional initializer is present, it is placed before the items of the iterable in the calculation, and serves as a default when the iterable is empty. If initializer is not given and iterable contains only one item, the first item is returned.

so reduce iteratively applies the passed in function, another lambda, to an array of arguments. the passed in function takes two arguments a,b and applies b to a

The iterable (fs+x)[::-1] has me confused, is it decrementing from the last arg? cycle through fs args (functions) one at a time until the index is -1 and keep applying it.

so magic_function(foo,bar)(x) would return
a function, foo(bar(x)) or is the order swapped and it returns bar(foo(x))

this matches up with what null_ptr identified

[–]null_ptr  1 point2 points3 points 18 hours ago* 

"The iterable (fs+x)[::-1] has me confused"

fs is a tuple of functions, say fs = (a, b, c). Doing (fs+x) makes it (a, b, c, x).

Now experimenting with [::x] in the python shell it looks like it steps through the tuple x elements at a time:

(a, b, c, x)[::1] = (a, b, c, x) (a, b, c, x)[::-1] = (x, c, b, a) (a, b, c, x)[::2] = (a, c) (a, b, c, x)[::-2] = (x, b) (a, b, c, x)[::3] = (a, x)

Now, reduce(lambda a,b: b(a), (fs+x)[::-1]) gets the reversed tuple (fs+x), meaning that x is the first element, so it's the initial value that reduce computes on. It then applies the functions one after the other, and since it was given (foo, bar) but the tuple is now (bar, foo), it first applies bar to x, and then foo to the result of that, giving you foo(bar(x)).