{"id":30,"date":"2007-10-20T15:09:46","date_gmt":"2007-10-20T17:09:46","guid":{"rendered":"http:\/\/www.ragestorm.net\/blogs\/?p=30"},"modified":"2007-10-20T18:32:58","modified_gmt":"2007-10-20T20:32:58","slug":"lambdas-forever","status":"publish","type":"post","link":"https:\/\/www.ragestorm.net\/blogs\/?p=30","title":{"rendered":"Lambdas Forever"},"content":{"rendered":"<p>Ahhh Python, what a splendid scripting language. One of the most likeable features is the anonymous functions, aka Lambda. The lambda is actually a way to write\/implement a simple one liner function in-place. The official docs says:<\/p>\n<p>&#8220;Lambda forms (lambda expressions) have the same syntactic position as expressions. They are a shorthand to create anonymous functions; the expression <code>lambda <var>arguments<\/var>: <var>expression<\/var><\/code> yields a function object.&#8221;<\/p>\n<p>Instead of implemented the damned comparison function for sorting, you probably all know what I&#8217;m talking about:<br \/>\ndef ComparisonProc(x, y):<br \/>\n\u00a0\u00a0\u00a0 return\u00a0\u00a0y &#8211; x<br \/>\nlist.sort(ComparisonProc)<\/p>\n<p>We can simply do:<br \/>\nlist.sort(lambda x, y:\u00a0y &#8211; x) # Descending<br \/>\nand voila.<\/p>\n<p>This is a very simple example. Lambdas are really handy when you want to do one liner devices. Some of them which you manage to stuff in one line and some which you just can&#8217;t. However, without lambda it wouldn&#8217;t have been possible in the first place.<\/p>\n<p>There are many samples in the Internet. I came up with something, hopefully even useful. Let&#8217;s say you want to print all .JPG files on your c:\\, including subdirectories. So we have to scan the h.d for all files, then filter those with .JPG extension and afterwards print the result. :) Yes this is all possible in one-liner, let&#8217;s see the original code first:<\/p>\n<p>for root, dirs, files in os.walk(&#8216;c:&#8217;):<br \/>\n\u00a0\u00a0\u00a0 for i in files:<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if i[-4:] == &#8220;.jpg&#8221;:<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print i<\/p>\n<p>The one-liner version:<\/p>\n<pre>\r\nprint filter(lambda name: name[-4:] == \".jpg\", reduce(lambda x,y:x+y, [i[2] for i in os.walk('c:')]))<\/pre>\n<p>See? Easy :)<\/p>\n<p>Actually now, I have to explain a few more things.<br \/>\n1) We are only interested in the Files list from os.walk, therefore we take the third entry in the result, that&#8217;s\u00a0i[2].<\/p>\n<p>2) The i[2] itself, is a list, and we cannot filter a list of lists with the file names, therefore we have to flatten the lists to a single list containing the file names. This is where the <em>reduce<\/em> comes in, it will return the <em>accumulated<\/em> result of all lambdas &#8211;\u00a0each time calling the lambda with the accumulated x and supplying the next item, y. Thus, adding the lists extends the resulting list and flatten them&#8230;<\/p>\n<p>3) Now that we the a single list with all file names in the system, we need to filter out the files which are not .JPG. So yet again we use a lambda that checks the last 4 characters in the file name and assures whether it is a .JPG, all other files will be removed from the resulting list.<\/p>\n<p>4) Lastly, print the result. Actually you can use pretty print (module pprint) to print it prettier :)<\/p>\n<p>\u00a0Yes, Python&#8217;s crazy!<\/p>\n<p>So what&#8217;s the annoying things with lambdas? They are slow relatively to list comprehensions (which we used to get all lists of file names above). But again, if we are using scripting &#8211; are we after speed? I am not sure. Another irritating thing about lambdas is that you cannot assign inside the expression, but then you have reduce.. :)<\/p>\n<p>The worst thing about lambdas is when you use global variables, and let me explain.\u00a0Since lambdas are evaluated at runtime (I hope I am right here) if you access some <em>variables<\/em> outside of the lambda, they will get re-evaluated everytime with the lambda itself. Now think that you wanted the lambda to have a specific value when you created the lambda, and then when you really <em>call<\/em> the lambda, that value was already changed and your result is screwed.<\/p>\n<p>Enough words, let&#8217;s see the problem\u00a0with some\u00a0code:<\/p>\n<p>&gt;&gt;&gt; x, y = [lambda z: 5+z+i\u00a0 for i in xrange(2)]<br \/>\n&gt;&gt;&gt; x(0)<br \/>\n6<br \/>\n&gt;&gt;&gt; y(0)<br \/>\n6<\/p>\n<p>Oh uh, we&#8217;re in trouble!<\/p>\n<p>Do you notice we get the same result for both functions? This is incorrect because they are not supposed to return the same value. Note this:<\/p>\n<p>&gt;&gt;&gt; i<br \/>\n1<\/p>\n<p>So now when both lambdas, x and y, are evaluated they use i as 1. Sucks huh?\u00a0<\/p>\n<p>&gt;&gt;&gt; i = 3<br \/>\n&gt;&gt;&gt; x(0)<br \/>\n8<br \/>\n&gt;&gt;&gt; y(0)<br \/>\n8<br \/>\n&#8220;Use Nested Lambdas, Luke&#8221;<\/p>\n<p>x, y = [(lambda v: lambda z: 5 + v)(i) for i in xrange(2)]<br \/>\n&gt;&gt;&gt; x, y = [(lambda v: lambda z: 5 + v)(i) for i in xrange(2)]<br \/>\n&gt;&gt;&gt; x(0)<br \/>\n5<br \/>\n&gt;&gt;&gt; y(0)<br \/>\n6<br \/>\n&gt;&gt;&gt;<\/p>\n<p>The outter lambda is get evaluated immediately and thus leaves the value, and not the pointer to the value, in the code. Next time when the inner lambda is evaluated it uses the <em>value-of(<\/em>i) and not the <em>value-from-pointer-of<\/em>(i).<\/p>\n<p>This surely will help someone out there :) And then they say Lambdas are going to be deprecated in Python 3000&#8230;<\/p>\n<p>[Updated]<\/p>\n<p>Thanks to Kasperle, here&#8217;s another solution to the nested lambdas:<\/p>\n<p>x, y = [lambda z, dummy = i: 5 + dummy for i in xrange(2)]<\/p>\n<p>The drawback is that x\u00a0and y can now get a second parameter which you potentially let the caller override&#8230;Or if we&#8217;re talking about Python 2.5 you can use functools.partial.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ahhh Python, what a splendid scripting language. One of the most likeable features is the anonymous functions, aka Lambda. The lambda is actually a way to write\/implement a simple one liner function in-place. The official docs says: &#8220;Lambda forms (lambda expressions) have the same syntactic position as expressions. They are a shorthand to create anonymous [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":""},"categories":[21,9],"tags":[],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pbWKd-u","_links":{"self":[{"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/posts\/30"}],"collection":[{"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=30"}],"version-history":[{"count":0,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/posts\/30\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=30"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=30"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=30"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}