{"id":912,"date":"2019-09-08T11:49:59","date_gmt":"2019-09-08T09:49:59","guid":{"rendered":"http:\/\/35.180.88.53\/?p=912"},"modified":"2019-10-28T12:50:25","modified_gmt":"2019-10-28T11:50:25","slug":"best-practices-for-using-functional-programming-in-python","status":"publish","type":"post","link":"https:\/\/www.sergilehkyi.com\/uk\/2019\/09\/best-practices-for-using-functional-programming-in-python\/","title":{"rendered":"Best Practices for Using Functional Programming in Python"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>Python is a very versatile, high-level programming language. It has a generous standard library, support for multiple programming paradigms, and a lot of internal transparency. If you choose, you can peek into lower layers of Python and modify them \u2013 and even modify the runtime on the fly as the program executes.<\/p>\n\n\n\n<p>I\u2019ve recently noticed an evolution in the way Python programmers use the language as they gain more experience. Like many new Python programmers, I appreciated the simplicity and user friendliness of the the basic looping, function, and class definition syntax when I was first learning. As I mastered basic syntax, I became curious about intermediate and advanced features like inheritance, generators, and metaprogramming. However, I wasn\u2019t quite sure when to use them, and would often jump at opportunities to practice that weren\u2019t a great fit. For a while, my code became more complex and harder to read. Then, as I kept iterating \u2013 especially if I kept working on the same codebase \u2013 I gradually reverted back to mostly using functions, loops, and singleton classes.<\/p>\n\n\n\n<p>With that being said, the other features exist for a reason, and they\u2019re important tools to understand. \u201cHow to write good code\u201d is obviously an expansive topic \u2013 and there\u2019s no single right answer! Instead, my goal with this blog post is to zero in on a specific aspect: functional programming as applied to Python. I\u2019ll dig into what it is, how it can be used in Python, and how&nbsp;\u2013 according to my experience \u2013 it\u2019s used best.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><\/strong>What is functional programming?<\/h2>\n\n\n\n<p>Functional programming, or FP, is a coding paradigm in which the building blocks are immutable values and \u201cpure functions\u201d that share no state with other functions. Every time a pure function has a given input, it will return the same output \u2013 without mutating data or causing side effects. In this sense, pure functions are often compared to mathematical operations. For example, 3 plus 4 will always equal 7, regardless of what other mathematical operations are being done, or how many times you\u2019ve added things together before.<\/p>\n\n\n\n<p>With the building blocks of pure functions and immutable values, programmers can create logical structures. Iteration can be replaced with recursion, because it is the functional way to cause the same action to occur multiple times. The function calls itself, with new inputs, until the parameters meet a termination condition. In addition, there are higher-order functions, which take in other functions as input and\/or return them as output. I\u2019ll describe some of these later on.<\/p>\n\n\n\n<p>Although functional programming has existed since the 1950s, and is implemented by a long lineage of languages, it doesn\u2019t fully describe a programming language. Clojure, Common Lisp, Haskell, and OCaml are all functional-first languages with different stances on other programming language concepts, like the type system and strict or lazy evaluation. Most of them also support side effects such as writing to and reading from files in some way or another \u2013 usually all very carefully marked as impure.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><\/strong>What does Python support?<\/h2>\n\n\n\n<p>Though Python is not primarily a functional language, it is able to support functional programming relatively easily because everything in Python is an object. That means that function definitions can be assigned to variables and passed around.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def add(a, b):\n    return a + b\n\nplus = add\n\nplus(3, 4)  # returns 7<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Lambda<\/h3>\n\n\n\n<p>The \u201clambda\u201d syntax allows you to create function definitions in a declarative way. The keyword lambda comes from the greek letter used in the formal mathematical logic for describing functions and variable bindings abstractly,&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/www.inf.fu-berlin.de\/lehre\/WS03\/alpi\/lambda.pdf\" target=\"_blank\">\u201clambda calculus\u201d<\/a>, which has existed for even longer than functional programming. The other term for this concept is \u201canonymous function\u201d, since lambda functions can be used in-line without ever actually needing a name. If you do choose to assign an anonymous function to a variable, they perform exactly the same as any other function.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(lambda a, b: a + b)(3, 4)  # returns 7\n\naddition = lambda a, b: a + b\naddition(3, 4)  # returns 7<\/code><\/pre>\n\n\n\n<p>The most common place I see lambda functions \u201cin the wild\u201d is for functions that take in a callable. A \u201ccallable\u201d is anything that can be invoked with parentheses \u2013 practically speaking classes, functions and methods. Amongst those, the most common use is to declare a relative prioritization via the argument key when sorting data structures.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>authors = ['Octavia Butler', 'Isaac Asimov', 'Neal Stephenson', 'Margaret Atwood', 'Usula K Le Guin', 'Ray Bradbury']\nsorted(authors, key=len)  # Returns list ordered by length of author name\nsorted(authors, key=lambda name: name.split()[-1])  # Returns list ordered alphabetically by last name.<\/code><\/pre>\n\n\n\n<p>The downside to inline lambda functions is that they show up with no name in stack traces, which can make debugging more difficult.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><\/strong>Functools<\/h3>\n\n\n\n<p>The higher-order functions that are the meat-and-potatoes of functional programming are available in Python either in builtins or via the functools library. map and reduce may ring a bell as a way to run distributed data analysis at scale, but they are also two of the most important higher-order functions. map applies a function to every item in a sequence, returning the resultant sequence, and reduce uses a function to collect every item in a sequence into a single value.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>val = [1, 2, 3, 4, 5, 6]\n\n# Multiply every item by two\nlist(map(lambda x: x * 2, val)) # [2, 4, 6, 8, 10, 12]\n# Take the factorial by multiplying the value so far to the next item\nreduce(lambda: x, y: x * y, val, 1) # 1 * 1 * 2 * 3 * 4 * 5 * 6<\/code><\/pre>\n\n\n\n<p>There are a pile of other higher order functions that manipulate functions in other ways, notably partial, which locks in some of the parameters to the function. This is also known as \u201ccurrying\u201d, a term named after FP pioneer Haskell Curry.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def power(base, exp):\n     return base ** exp\ncube = partial(power, exp=3)\ncube(5)  # returns 125<\/code><\/pre>\n\n\n\n<p>For a detailed tour of introductory FP concepts in Python, written in the way a functional-first language would use them, I recommend Mary Rose Cook\u2019s article&nbsp;<a href=\"https:\/\/maryrosecook.com\/blog\/post\/a-practical-introduction-to-functional-programming\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><\/strong>Decorators<\/h3>\n\n\n\n<p>Higher-order functions are also baked into everyday Python via decorators. One way of declaring decorators reflects that, and the @ symbol is basically a syntactic sugar for passing in the decorated function as an argument to the decorator. Here is a simple decorator that sets up retries around a piece of code and returns the first successful value, or gives up and raises the most recent exception after 3 attempts.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def retry(func):\n    def retried_function(*args, **kwargs):\n        exc = None\n        for _ in range(3):\n            try:\n               return func(*args, **kwargs)\n            except Exception as exc:\n               print(\"Exception raised while calling %s with args:%s, kwargs: %s. Retrying\" % (func, args, kwargs).\n\n        raise exc\n     return retried_function\n\n@retry\ndef do_something_risky():\n    ...\n\nretried_function = retry(do_something_risky)  # No need to use `@`<\/code><\/pre>\n\n\n\n<p>This decorator leaves the input and output types and values as exactly the same \u2014 but that\u2019s not a requirement. Decorators can add or remove arguments or change their type. They can also be configured via parameters themselves. I want to stress that decorators themselves are not necessarily \u201cpurely functional\u201d; they can (and often do, as in the example above) have side effects \u2013 they just happen to use higher order functions.<\/p>\n\n\n\n<p>Like many intermediate or advanced Python techniques, this is very powerful and often confusing. The name of the function you called will be different from the name in the stack traces, unless you use the functools.wraps decorator to annotate. I have seen decorators do very complicated or important things, like parse values out of json blobs or handle authentication. I\u2019ve also seen multiple layers of decorators on the same function or method definition, which requires knowing the decorator application order to understand. I think it can be helpful to use the builtin decorators like `staticmethod` or write simple, clearly named decorators that save a lot of boilerplate, but especially if you want to make your code compatible with type checking, anything that changes the input or output types can easily edge into \u201ctoo clever\u201d.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><\/strong>My recommendations<\/h2>\n\n\n\n<p>Functional programming is interesting, and learning paradigms that are outside your current comfort zone is always good for building flexibility and allowing you to look at problems in different ways. However, I wouldn\u2019t recommend writing a lot of functional-first Python, especially in a shared or long-lived codebase. Aside from the pitfalls of each feature I mentioned above, here\u2019s why:<\/p>\n\n\n\n<ul><li>In order to begin using Python, it\u2019s not required to understand FP. You\u2019re likely to confuse other readers, or your future self.<\/li><li>You have no guarantee that any of the code you rely on (pip modules or your collaborators\u2019 code) is functional and pure. You also don\u2019t know whether your own code is as pure as you hope for it to be \u2013 unlike functional-first languages, the syntax or compiler don\u2019t help enforce purity and help eliminate some types of bugs. Mashing up side effects and higher level functions can be extremely confusing, because you end up with two kinds of complexity to reason through, and then the multiplicative effect of the two together.<\/li><li>Using higher-order function with type comments is an advanced skill. Type signatures often become long and unwieldy nests of&nbsp;<code>Callable<\/code>. For example, the correct way to type a simple higher order decorator that returns the input function is by declaring&nbsp;<code>F = TypeVar[\u2018F\u2019, bound=Callable[..., Any]]<\/code>&nbsp;then annotating as&nbsp;<code>def transparent(func: F) -&gt; F: return func<\/code>. Or, you may be tempted to bail and use&nbsp;<code>Any<\/code>&nbsp;instead of trying to figure out the correct signature.<\/li><\/ul>\n\n\n\n<p>So what parts of functional programming should be used?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><\/strong>Pure functions<\/h3>\n\n\n\n<p>When possible and reasonably convenient, try to keep functions \u201cpure\u201d, and keep state that changes in well-thought-out, well marked places. This makes unit testing a lot easier \u2013 you avoid having to do as much set-up, tear-down, and mocking, and the tests are more likely to be predictable regardless of the order they run in.<\/p>\n\n\n\n<p>Here is a non-functional example.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dictionary = ['fox', 'boss', 'orange', 'toes', 'fairy', 'cup']\ndef puralize(words):\n   for i in range(len(words)):\n       word = words[i]\n       if word.endswith('s') or word.endswith('x'):\n           word += 'es'\n       if word.endswith('y'):\n           word = word[:-1] + 'ies'\n       else:\n           word += 's'\n       words[i] = word\n\ndef test_pluralize():\n    pluralize(dictionary)\n    assert dictionary == ['foxes', 'bosses', 'oranges', 'toeses', 'fairies', 'cups']<\/code><\/pre>\n\n\n\n<p>The first time you run&nbsp;<code>test_pluralize<\/code>, it will pass, but every time after it\u2019s going to fail, as the&nbsp;<code>s<\/code>&nbsp;and&nbsp;<code>es<\/code>get appended ad infinitum. To make it a pure function, we could rewrite it as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dictionary = ['fox', 'boss', 'orange', 'toes', 'fairy', 'cup']\ndef puralize(words):\n   result = []\n   for word in words:\n       word = words[i]\n       if word.endswith('s') or word.endswith('x'):\n           plural = word + 'es')\n       if word.endswith('y'):\n           plural = word[:-1] + 'ies'\n       else:\n           plural = +  's'\n       result.append(plural)\n    return result\n\ndef test_pluralize():\n    result = pluralize(dictionary)\n    assert result == ['foxes', 'bosses', 'oranges', 'toeses', 'fairies', 'cups']<\/code><\/pre>\n\n\n\n<p>Note that I\u2019m not actually using FP-specific concepts, but rather just making and returning a new object instead of mutating and reusing the old one. This way, if anyone has a reference remaining to the input list they won\u2019t be surprised.<\/p>\n\n\n\n<p>This is a bit of a toy example, but imagine instead you\u2019re passing in and mutating some complex object, or maybe even doing operations via a connection to a database. You\u2019ll probably want to write many types of test cases, but you\u2019d have to be very careful about the order or deal with cost of wiping and recreating state. That kind of effort is best saved for end-to-end integration tests, not smaller unit tests.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><\/strong>Understanding (and avoiding) mutability<\/h3>\n\n\n\n<p>Why is this important? Sometimes lists and tuples feel interchangeable, and it\u2019s tempting to write code that uses a random combination of the two. Then tuples error as soon as you try to do a mutation operation such as assigning to an element. Or, you try to use a list as a dictionary key, and see a&nbsp;<code>TypeError<\/code>, which occurs precisely because lists are mutable. Tuples and strings can be used as dictionary keys because they\u2019re immutable and can be deterministically hashed, and all the other data structures can\u2019t because they might change in value even when the object identity is the same.<\/p>\n\n\n\n<p>Most importantly, when you pass around dicts\/lists\/sets, they can be mutated unexpectedly in some other context. This is a mess to debug. The mutable default parameter is a classic case of this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def add_bar(items=[]):\n    items.append('bar')\n    return items\n\nl = add_bar()  # l is ['bar']\nl.append('foo')\nadd_bar() # returns ['bar', 'foo', 'bar']<\/code><\/pre>\n\n\n\n<p>Dictionaries, sets and lists are powerful, performant, Pythonic and extremely useful. Writing code without them would be inadvisable. That being said, I always use a tuple or None (swapping it out for an empty dict or list later) as default parameters, and I try to avoiding passing mutable data structures around from context to context without being on guard to the fact they might be modified.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><\/strong>Limiting use of classes<\/h3>\n\n\n\n<p>Often, classes (and their instances) carry that double-edged sword of mutability. The more I program in Python, the more I put off making classes until they\u2019re clearly necessary, and I almost never use mutable class attributes. This can be hard for those coming from highly object oriented languages like Java, but many things that are usually or always done via a class in another language are fine to keep at the module level in Python. For example, if you need to group functions or constants or namespace then, they can be put into a separate .py file together.<\/p>\n\n\n\n<p>Frequently, I see classes used to hold a small collection of variable names with values, when a namedtuple (or&nbsp;<code>typing.NamedTuple<\/code>&nbsp;for type specificity) would work just as well, and be immutable.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from collections import namedtuple\nVerbTenses = namedtuple('VerbTenses', ['past', 'present', 'future'])\n# versus\nclass VerbTenses(object):\n    def __init__(self, past, present, future):\n        self.past = past,\n        self.present = present\n        self.future = future<\/code><\/pre>\n\n\n\n<p>If you do need to provide a source of state, and multiple views into that state and ways to change it, then classes are an excellent choice. In addition, I tend to prefer singleton pure functions over static methods, so they can be used composably in other contexts.<\/p>\n\n\n\n<p>Mutable class attributes are highly dangerous, because they belong to the class definition rather than the instance, so you can end up accidentally mutating state across multiple instances of the same class!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Bus(object):\n     passengers = set()\n     def add_passenger(self, person):\n        self.passengers.add(person)\n\nbus1 = Bus()\nbus2 = Bus()\nbus1.add_passenger('abe')\nbus2.add_passenger('bertha')\nbus1.passengers  # returns ['abe', 'bertha']\nbus2.passengers  # also ['abe', 'bertha']<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><\/strong>Idempotency<\/h3>\n\n\n\n<p>Any realistic, large and complex system has occasions when it will have to fail and retry. The concept \u201cidempotency\u201d exists in API design and matrix algebra as well, but within functional programming, an idempotent function returns the same thing when you pass in previous output. Therefore, redoing something always converges to the same value. A more useful version of the \u2018pluralize\u2019 function above would check if something was already in plural form before trying to calculate how to make it plural, for example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><\/strong>Sparing use of lambdas and higher order functions<\/h3>\n\n\n\n<p>I find it often quicker and clearer to use lambdas in the case of short operations like in an ordering key for&nbsp;<code>sort<\/code>. If a lambda gets longer than one line, however, a regular function definition is probably better. And passing functions around in general can be useful for avoiding repetition, but I try to keep in mind whether the extra structure obscures the clarity too much. Often times, breaking out into smaller composable helpers is clearer.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><\/strong>Generators and higher level functions, when necessary<\/h3>\n\n\n\n<p>Occasionally you will encounter an abstract generator or iterator, maybe one that returns a large or even infinite sequence of values. A good example of this is range. In Python 3, it is now a generator by default (equivalent to xrange in Python 2), in part to save you from out-of-memory errors when you try iterate over a large number, like range(10**10). If you want to do some operation on every item in a potentially-large generator, then using tools like map and filter may be the best option.<\/p>\n\n\n\n<p>Similarly, if you don\u2019t know how many values your newly written iterator might return \u2014 and it\u2019s likely large \u2014 defining a generator could be the way to go. However, not everyone will be savvy about consuming it, and may decide to collect the result in a list comprehension, resulting in the OOM error you were trying to avoid in the first place. Generators, Python\u2019s implementation of stream programming, are also not necessarily purely functional \u2013 so all the same caveats around safety apply as any other style of Python programming.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><\/strong>Concluding thoughts<\/h2>\n\n\n\n<p>Getting to know your programming language of choice well by exploring its features, libraries and internals will undoubtedly help you debug and read code faster. Knowing about and using ideas from other languages or programing language theory can also be fun, interesting, and make you a stronger and more versatile programmer. However, being a Python power-user ultimately means not just knowing what you *could* do, but understanding when which skills would be more efficient. Functional programming can be incorporated into Python easily. To keep its incorporation elegant, especially in shared code spaces, I find it best to use a purely functional mindset to make code more predictable and easy, all the while maintaining simplicity and idiomaticity.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p><em>This article was originally published at&nbsp;<a href=\"https:\/\/kite.com\/blog\/python\/functional-programming\/\">Kite\u2018s<\/a>&nbsp;blog and republished here as part of content partnership program.&nbsp;<a href=\"https:\/\/kite.com\/\">Kite<\/a>&nbsp;is a plugin for your IDE that uses machine learning to give you&nbsp;useful code completions for Python. Available for Atom, PyCharm, Sublime, VS Code, and Vim.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Python is a very versatile, high-level programming language. It has a generous standard library, support for multiple programming paradigms,&hellip;<\/p>\n","protected":false},"author":1,"featured_media":913,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,5],"tags":[],"translation":{"provider":"WPGlobus","version":"3.0.0","language":"uk","enabled_languages":["gb","es","uk"],"languages":{"gb":{"title":true,"content":true,"excerpt":false},"es":{"title":false,"content":false,"excerpt":false},"uk":{"title":false,"content":false,"excerpt":false}}},"_links":{"self":[{"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/posts\/912"}],"collection":[{"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/comments?post=912"}],"version-history":[{"count":4,"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/posts\/912\/revisions"}],"predecessor-version":[{"id":1026,"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/posts\/912\/revisions\/1026"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/media\/913"}],"wp:attachment":[{"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/media?parent=912"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/categories?post=912"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sergilehkyi.com\/uk\/wp-json\/wp\/v2\/tags?post=912"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}