Functional programming in Python: a little bit more

Anderson Resende
May 25, 2016
<p>In our <a href="http://www.vinta.com.br/blog/2015/functional-programming-python.html">first blog post of functional programing in Python</a>, we talked about the main concepts and showed the most important functional constructs in Python. For this blog post I will assume you already read the first part, because we will go deeper into some concepts now. Bear in mind that all examples that follow will be provided in Python3.</p><p>This blog entry has two main goals. The first one is to help you understand what is function composition. In the second goal, we will deal with two of the best Python modules: <strong>operator</strong> and <strong>functools</strong>, which can be used to construct better high-order functions and will also help you to do function composition. That way we can easily combine functions we already built, leaving code more declarative. Let's see how.</p><h1 id="function-composition-made-easy">Function Composition made easy</h1><p>Before we start, let me explain a little about function composition. To say it simple it is when your function is composed by other functions internally.</p><p>Take a look at the code below:</p><pre><code class="language-python">def clean_and_lower(text): return text.strip().lower() print(clean_and_lower("Anderson ")) # prints anderson </code></pre><p>The function <code>clean_and_lower</code> is composed by both <code>strip</code> and <code>lower</code> functions. First the text is striped off blanks and then the result is showed in lower case.</p><p>Let's write an function to help us to do a simple composition:</p><pre><code class="language-python">def compose(f1, f2): return lambda x: f1(f2(x)) # returns a new funcion composed by the functions passed as argument </code></pre><p>Now, we can use that function as follows:</p><pre><code class="language-python">clean_and_lower = compose(str.lower, str.strip) # returns the composed function print(clean_and_lower("Anderson ")) # also prints anderson </code></pre><p>Think of it as if we were plaing with Lego. There are blocks that we can put together to do something more complex. By using function composition we can combine a lot of functions into other functions and so, the code becomes more declarative. This is one of the main concepts in functional programming.</p><h1 id="operator-contributing-towards-the-use-of-high-order-functions">Operator: contributing towards the use of high-order functions</h1><p>The <strong>operator</strong> module provides a lot of functions to perform basic operations that can be used isolated or combined with other functions.</p><p>Check the code below:</p><pre><code class="language-python">result = 1 + 2 print(result) # prints 3 import operator result = operator.add(1, 2) print(result) # prints 3 too, operator.add is only a function that performs addition print('A'+'B') # prints AB print(operator.concat("A", "B")) # prints AB too </code></pre><p>There are a lot of other functions like <code>operator.eq</code>, <code>operator.gt</code> and others. I know that you may be wondering why one would use <strong>operator</strong> instead of simply using <code>1 + 2</code>. I will show you when to use this module and why it's waaay better to use <strong>operator</strong> as High-order functions.</p><h1 id="functools-a-walk-in-the-park">Functools, a walk in the park</h1><p>Let’s start showing the <code>reduce</code> function, that receives one function and a array of values and combine them together, returning a single value. Remember to import the functools module.</p><pre><code class="language-python">import functools </code></pre><p>Let’s sum a list of numbers:</p><pre><code class="language-python">print(functools.reduce(lambda a, b: a+b, [3, 5, 2, 1], 0)) # prints 11 </code></pre><p>In the example above the lambda function receives two values and sums them. The <code>reduce</code> function iterates the list while applying the function, combining results until a single <code>11</code> value is computed.</p><p>Look the image below to understand how <code>reduce</code> works:</p><figure class="kg-card kg-image-card"><img src="https://vinta-cms.s3.amazonaws.com/media/filer_public/43/7a/437a971a-37eb-45b3-ac8d-7d536517136c/reduce.png" class="kg-image" alt="reduce.png"></figure><p>Take a look now how we can replace the <code>lambda</code> function by using the <code>operator.add</code>.</p><pre><code class="language-python">print(functools.reduce(operator.add, [3, 5, 2, 1], 0)) # prints 11 </code></pre><p>Easy peasy, right? The code is simpler and more declarative using <code>operator.add</code>.</p><p>Let’s use again with the <code>operator.concat</code>:</p><pre><code class="language-python">print(functools.reduce(operator.concat, ["Reduce", " is", " Awesome!"])) # prints Reduce is Awesome </code></pre><p>Other important function is <code>partial</code>, which is also present in the <strong>functools</strong> module. The partial function is used to facilitate the composition of other functions.</p><p>Check the example below using the <code>operator.concat</code>:</p><pre><code class="language-python">call_me_mr = functools.partial(operator.concat, "Mr ") call_me_mrs = functools.partial(operator.concat, "Mrs ") </code></pre><p>The <code>partial</code> function receives one function, in the case above the <code>operator.concat</code>. One second argument is passed, in our case, the value <code>Mr </code>. In that way we get back another function that expects the second value of the <code>operator.concat</code>.</p><pre><code class="language-python">print(call_me_mr("Anderson")) # prints Mr Anderson print(call_me_mrs("Renata")) # prints Mrs Renata </code></pre><p>See? You can interpret <code>call_me_mr</code> as a partial application of <code>operator.concat</code>. It's partial because it's missing the second argument, which we pass later by calling <code>call_me_mr</code>.</p><p>Let’s see an example a little bit more interesting of the use of <code>partial</code>. We'll combine partial with the <code>sorted</code> function and the <code>operator.attrgetter</code> function:</p><pre><code class="language-python">person = namedtuple('Person', 'name age') p1 = person('Anderson', 29) p2 = person('Renato', 25) p3 = person('Diego', 27) persons = [p1, p2, p3] # a list of persons sort_by_name = functools.partial(sorted, key=lambda t: t.name) # returns one function that order by name sort_by_age = functools.partial(sorted, key=lambda t: t.age) # returns one function that order by age print(sort_by_name(persons)) # prints Anderson, Diego and Renato print(sort_by_age(persons)) # prints Renato, Diego, Anderson </code></pre><p>How about replacing those lambda functions for <code>operator.attrgetter</code>?</p><pre><code class="language-python">sort_by_name = functools.partial(sorted, key=operator.attrgetter('name')) sort_by_age = functools.partial(sorted, key=operator.attrgetter('age')) </code></pre><p>We get the same result with a more declarative code.</p><h1 id="sum-up">Sum-up</h1><p>We introduced some intermediate functional programming concepts, as partial and function composition, applying them using Python. Challenge yourself to see in which moments you can use partial, doing function composition. You will see how this is cool. Also check by yourself the <a href="https://docs.python.org/3/library/functools.html">functools</a> and <a href="https://docs.python.org/3/library/operator.html">operator</a> modules.</p><h1 id="references">References</h1><p><a href="http://learnyouahaskell.com/higher-order-functions#folds">http://learnyouahaskell.com/higher-order-functions#folds</a></p>