4 ms·
The former is absolutely identical (semantically) to the latter, with two exceptions: 1) the former function does not know its own name and 2) the latter functi
by aaronchall 11y ago
The former is absolutely identical (semantically) to the latter, with two exceptions: 1) the former function does not know its own name and 2) the latter function can (and should) be documented with a docstring. I find the latter eminently more readable, and I work daily in a code base under development by 3000 Python developers for over 5 years.
Considering that the creator of the Python language considered getting rid of lambdas because they are essentially limited functions and thus violate Python's "one obvious way to do it" philosophy, I'd rather those learning Python to be shown the latter, rather than the former.
From a development and version control perspective, as soon as the lambda function requires more than a simple expression, i.e. a compound statement (https://docs.python.org/2/reference/compound_stmts.html https://docs.python.org/2/reference/compound_stmts.html), you have to trash the whole line, instead of adding perhaps a single extra line of content.
- merlincorey 11y ago> The former is absolutely identical to the latter Oh, really? Let's compare: >>> absolute_0 = lambda path: path if path.startswith('/') else '/' + path >>> def absolute_1(path): ... '''Return the absolute unix path from a given path name''' ... if not path.startswith('/'): ... path = '/' + path ... return path >>> import dis >>> dis.dis(absolute_0) 2 0 LOAD_FAST 0 (path) 3 LOAD_ATTR 0 (startswith) 6 LOAD_CONST 1 ('/') 9 CALL_FUNCTION 1 12 POP_JUMP_IF_FALSE 19 15 LOAD_FAST 0 (path) 18 RETURN_VALUE >> 19 LOAD_CONST 1 ('/') 22 LOAD_FAST 0 (path) 25 BINARY_ADD 26 RETURN_VALUE >>> dis.dis(absolute_1) 4 0 LOAD_FAST 0 (path) 3 LOAD_ATTR 0 (startswith) 6 LOAD_CONST 1 ('/') 9 CALL_FUNCTION 1 12 POP_JUMP_IF_TRUE 28 5 15 LOAD_CONST 1 ('/') 18 LOAD_FAST 0 (path) 21 BINARY_ADD 22 STORE_FAST 0 (path) 25 JUMP_FORWARD 0 (to 28) 6 >> 28 LOAD_FAST 0 (path) 31 RETURN_VALUE These functions are actually not identical in their computation - only their result. > 1) the former function does not know its own name If you think that is really important (hint: it's not [from a lisper perspective, anyway]), Python thankfully allows you to do this: >>> absolute_0.__name__ '<lambda>' >>> absolute_0.__name__ = '<lambda "absolute_0">' >>> absolute_0.__name__ '<lambda "absolute_0">' > 2) the latter function can be documented with a docstring >>> absolute_0.__doc__ >>> absolute_0.__doc__ = 'Return the absolute unix path from a given path name' >>> help(absolute_0) Help on function <lambda "absolute_0">: <lambda "absolute_0">(path) Return the absolute unix path from a given path name Of course the only reason you can't put docstrings on a lambda function in python is because the forced indentation of code and implicit return with no indented block available is what Guido went with for Lambda. > Considering that the creator of the Python language considered getting rid of lambdas Guido is not a proponent of functional programming in general and claims that map, reduce, and filter are so much harder to understand than list comprehensions (which implement some common map, reduce, and filter, operations with special optimized syntax) that he tried to get them removed from the language too. Thankfully for us users of the language, this view did not win through and we can still use map, reduce, and filter in python, if we choose.
- aaronchall 11y agoSpare us the half-baked hackery. List comprehensions and generator expressions have replaced all need for map, filter, and lambdas, and are far more readable. For someone new to Python, halfway through LPTHW, they don't need those things. Hey, maybe you can help me decipher this, I've always wondered exactly what's going on here: https://docs.python.org/2/faq/programming.html#is-it-possible-to-write-obfuscated-one-liners-in-python https://docs.python.org/2/faq/programming.html#is-it-possibl... # Mandelbrot set print (lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y, Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM, Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro, i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y >=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr( 64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy ))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24) # \___ ___/ \___ ___/ | | |__ lines on screen # V V | |______ columns on screen # | | |__________ maximum of "iterations" # | |_________________ range on y axis # |____________________________ range on x axis
- merlincorey 11y ago> Spare us the half-baked hackery. Ad hominem? I guess I win. > List comprehensions and generator expressions have replaced all need for map, filter, and lambdas Please explain how list comprehensions and generators have replaced the need for lambdas. >>> sorted(((x, -(x**2)) for x in xrange(10) if 0 == x % 2), key=lambda item: item[1]) [(8, -64), (6, -36), (4, -16), (2, -4), (0, 0)] Your "distaste" of functional programming constructs is right up there with Guido's.
- aaronchall 11y agoNice lambda. You've defended yourself admirably. Did you know there's an `operator.itemgetter` function that does that? So that's: >>> sorted(((x, -(x**2)) for x in xrange(10) if 0 == x % 2), key=operator.itemgetter(1)) [(8, -64), (6, -36), (4, -16), (2, -4), (0, 0)] Do note that good code and code golf are two different things! :D