I have always thought that functional programming can be done in Python. Thus, I was surprised that Python didn't get much of a mention in this question, and when it was mentioned, it normally wasn't very positive. However, not many reasons were given for this (lack of pattern matching and algebraic data types were mentioned). So my question is: why isn't Python very good for functional programming? Are there more reasons than its lack of pattern matching and algebraic data types? Or are these concepts so important to functional programming that a language that doesn't support them can only be classed as a second rate functional programming language? (Keep in mind that my experience with functional programming is quite limited.)
-
32018 - [Coconut](http://coconut-lang.org/) *(a functional programming language that compiles to Python)* enhances functional programming in Python. See also this series of articles from IBM [page1](http://www.eecg.toronto.edu/~jzhu/csc326/readings/functional-charming1.pdf) [page2](http://www.eecg.toronto.edu/~jzhu/csc326/readings/functional-charming2.pdf) [page3](http://www.eecg.toronto.edu/~jzhu/csc326/readings/functional-charming3.pdf) – cssyphus Nov 16 '18 at 19:43
9 Answers
The question you reference asks which languages promote both OO and functional programming. Python does not promote functional programming even though it works fairly well.
The best argument against functional programming in Python is that imperative/OO use cases are carefully considered by Guido, while functional programming use cases are not. When I write imperative Python, it's one of the prettiest languages I know. When I write functional Python, it becomes as ugly and unpleasant as your average language that doesn't have a BDFL.
Which is not to say that it's bad, just that you have to work harder than you would if you switched to a language that promotes functional programming or switched to writing OO Python.
Here are the functional things I miss in Python:
- Pattern matching
- Tail recursion
- Large library of list functions
- Functional dictionary class
- Automatic currying
- Concise way to compose functions
- Lazy lists
- Simple, powerful expression syntax (Python's simple block syntax prevents Guido from adding it)
- No pattern matching and no tail recursion mean your basic algorithms have to be written imperatively. Recursion is ugly and slow in Python.
- A small list library and no functional dictionaries mean that you have to write a lot of stuff yourself.
- No syntax for currying or composition means that point-free style is about as full of punctuation as explicitly passing arguments.
- Iterators instead of lazy lists means that you have to know whether you want efficiency or persistence, and to scatter calls to
list
around if you want persistence. (Iterators are use-once) - Python's simple imperative syntax, along with its simple LL1 parser, mean that a better syntax for if-expressions and lambda-expressions is basically impossible. Guido likes it this way, and I think he's right.

- 78,177
- 11
- 137
- 148

- 18,329
- 4
- 46
- 56
-
5+1 for missing tail recursion - though looping constructs have superseded it, its still something worth missing going between Python and Scheme. – new123456 Apr 17 '11 at 23:09
-
6Excellent answer as for completeness and composition. Alas, like with so many answers with a strong functional background, it has IMO abusive use of terminology. While I understand that you cannot elaborate on each concept in an answer, I wonder if the OP (with admitted limited FP background) is well-informed when reading terms like "pattern matching", "functional dictionaries", "currying", or "lazy lists". – ThomasH May 06 '11 at 10:32
-
5Good point; I think the solution is to add links. Do you have enough rep to edit my answer? If so feel free to add links to the various concepts. I will start when I have time later. – Nathan Shively-Sanders Jun 09 '11 at 15:27
-
7I realize this is 5 years old, but… this seems like it's more about the things you miss _from Haskell_, not from _functional languages_. For example, most ML and Lisp dialects and descendants don't have automatic currying, make point-free style overly verbose, don't have lazy lists, etc. So, if iterators instead of lazy lists makes Python a bad functional language, having _neither_ must make CaML a _terrible_ functional language? – abarnert Nov 13 '14 at 01:23
-
1This is still a very good answer. It just seems like it should be clearer in what it's saying:, which I think is something like, "Python isn't as good a functional language as Haskell, and if you don't like Haskell, nearly every cool feature can be found in or added to some _other_ functional language… but not in or to Python" – abarnert Nov 13 '14 at 01:25
-
4@abarnert: Caml has every bullet point except lazy lists, which are available as a library. I occasionally used Caml at the time I wrote this answer and currently use F#. They are both very nice functional languages. – Nathan Shively-Sanders Nov 13 '14 at 18:05
-
1Dear @NathanShively-Sanders, since you have nailed the question and got that high marks, you may additionally provide a link to the new extension-language for Python addressing ALL the points you list: [cocount](http://coconut-lang.org/) – ankostis Jul 04 '16 at 12:59
-
3Just a note, as I checked @ankostis answer : I read it as the fact that "cocount" was an extension to the python language. This is actually another language that is backward compatible to python and transpiles into python. And unfortunately, it's not called cocount, but coconut :( – bartavelle Oct 10 '16 at 15:33
-
Your list of missing features is quite good. And shows that python is *quite bad* at functional programming. – WestCoastProjects May 23 '18 at 22:54
-
1You can fairly successfully replace lazy lists with generators in python, especially with generator comprehensions. They don't allow you traverse the list more then once, but if you need that, just convert it to a non-lazy list. – Hjulle Aug 26 '18 at 17:18
-
1While they aren't all methods of `list`, I'll note that the vast majority of the functionality in your `Data.List` docs link is available as one of: 1) A `list` method, 2) A built-in that works on arbitrary iterables, or 3) A function from the `itertools` or `functools` modules that works on arbitrary iterables. Sure, fewer people know the std lib and might miss #3 (even some of #2), but most of the functionality exists w/o reinventing it. I'd also argue "Large set of `list` functions" is unrelated to "functional"; [Lisp gets by with eight](https://www.tutorialspoint.com/lisp/lisp_lists.htm). – ShadowRanger Apr 24 '19 at 16:39
-
@ShadowRanger itertools has 20 functions in it, and functools doesn't have anything to do with lists. That's consistent with working-but-not-promoting. Also, the Common Lisp Hyperspec lists about 80 functions: http://www.lispworks.com/documentation/HyperSpec/Body/c_conses.htm http://www.lispworks.com/documentation/HyperSpec/Body/c_sequen.htm Edit: Also note that Lisp only has 2-3 of the functional features I missed in Python. (Depending on whether your lisp guarantees tail call elimination -- Common Lisp does not.) – Nathan Shively-Sanders Jun 07 '19 at 18:02
-
Lack of static typing is a huge problem. F# by contrast has great static typing. – silvalli Apr 01 '23 at 18:59
Guido has a good explanation of this here. Here's the most relevant part:
I have never considered Python to be heavily influenced by functional languages, no matter what people say or think. I was much more familiar with imperative languages such as C and Algol 68 and although I had made functions first-class objects, I didn't view Python as a functional programming language. However, earlier on, it was clear that users wanted to do much more with lists and functions.
...
It is also worth noting that even though I didn't envision Python as a functional language, the introduction of closures has been useful in the development of many other advanced programming features. For example, certain aspects of new-style classes, decorators, and other modern features rely upon this capability.
Lastly, even though a number of functional programming features have been introduced over the years, Python still lacks certain features found in “real” functional programming languages. For instance, Python does not perform certain kinds of optimizations (e.g., tail recursion). In general, because Python's extremely dynamic nature, it is impossible to do the kind of compile-time optimization known from functional languages like Haskell or ML. And that's fine.
I pull two things out of this:
- The language's creator doesn't really consider Python to be a functional language. Therefore, it's possible to see "functional-esque" features, but you're unlikely to see anything that is definitively functional.
- Python's dynamic nature inhibits some of the optimizations you see in other functional languages. Granted, Lisp is just as dynamic (if not more dynamic) as Python, so this is only a partial explanation.

- 28,719
- 15
- 79
- 106

- 192,085
- 135
- 376
- 510
-
9You can do tail call optimization in Python just fine. Guido doesn't/didn't understand that. – Jules Jun 19 '09 at 12:27
-
29It seems to boil down to that Guido van Rossum _doesn't_like_ functional style. – Svante Jun 19 '09 at 14:02
-
64I think it's more accurate to say that Guido van Rossum doesn't understand functional style, and doesn't understand why Python needs them. You have to understand two things: 1) programming languages are at the bottom of a technology stack and affect everything built upon them and 2) just like any other piece of software, it's easier to add features than it is to remove them. So I think it's a good quality for a language designer to be critical of these kinds of requests. – Jason Baker Jun 19 '09 at 14:45
-
8
-
6@Jules, do you mind sharing a guideline for the use of tail call optimization in Python? A pointer to some source would be useful. – David Shaked Jan 25 '16 at 21:39
Scheme doesn't have algebraic data types or pattern matching but it's certainly a functional language. Annoying things about Python from a functional programming perspective:
Crippled Lambdas. Since Lambdas can only contain an expression, and you can't do everything as easily in an expression context, this means that the functions you can define "on the fly" are limited.
Ifs are statements, not expressions. This means, among other things, you can't have a lambda with an If inside it. (This is fixed by ternaries in Python 2.5, but it looks ugly.)
Guido threatens to remove map, filter, and reduce every once in a while
On the other hand, python has lexical closures, Lambdas, and list comprehensions (which are really a "functional" concept whether or not Guido admits it). I do plenty of "functional-style" programming in Python, but I'd hardly say it's ideal.
-
3Map, filter, and reduce really aren't needed in python. I have yet to see a piece of code that was simplified very much by using them. Plus, calling functions in Python can be expensive, so it's usually better just to use a list/generator comprehension or a for loop anyway. – Jason Baker Jun 19 '09 at 13:54
-
2This is exactly what Nathan Sanders says below: "Python does not promote functional programming even though it works fairly well." If Guido wanted Python to become a functional language, he'd make the implementation work well enough to use throwaway functions, and would uncripple Lambdas to the extent that you can actually use map/filter/reduce in useful ways. On the other hand, functional people are starting to wake up to the awesomeness of list comprehensions. Hopefully we won't have to pick one or the other. – Jacob B Jun 19 '09 at 14:14
-
7map and filter are trivially replace by a list comprehension. reduce -- almost always -- it so inefficient that it should be replaced with a generator function. – S.Lott Jun 19 '09 at 14:33
-
13
-
17@JacobB List comprehensions were available in functional languages about 15 years before Python was invented and 25 years before Python gained an implementation of the feature. The idea that Python has influenced their spread, or that fp learned this from Python, or even simply that it's popularity in the fp world post-dates the Python implementation, is simply wrong. Python's implementation was taken directly from Haskell. Maybe I've misunderstood you and that's not what you meant, but I am perplexed by "functional people are *starting* to wake up to the awesomeness of list comprehensions". – itsbruce Jul 18 '14 at 14:23
-
@JasonBaker "`map`/`filter`/`reduce` are not needed" : that is from a perspective of someone who does not use functional programming. Those *are* the fundamentals of `functionals`. Those alone make even `javascript` a much better language for functional programming than python. `Crippled lambdas` is under-appreciated as the other huge miss in python . Due to generators instead of fully baked we also have to put `list(blah)` everywhere - which when composing a half dozen functions imposes 6 `list(blah)'`. Ridiculous to try to read that. – WestCoastProjects Aug 01 '20 at 14:10
I would never call Python “functional” but whenever I program in Python the code invariably ends up being almost purely functional.
Admittedly, that's mainly due to the extremely nice list comprehension. So I wouldn't necessarily suggest Python as a functional programming language but I would suggest functional programming for anyone using Python.

- 530,221
- 131
- 937
- 1,214
-
1List comprehensions are tricky at two levels already: three is unreadable. With a language supporting `functionals`, `builder`s, chaining, and `lambda`'s that are not crippled (as mentioned in another answer above) we can put an arbitrary number of operations sequentially . This is not possible in `python` without obscure third party libraries: and is still limited (due to crippled `lambdas`) even with them.. See https://stackoverflow.com/questions/49001986/left-to-right-application-of-operations-on-a-list-in-python3 – WestCoastProjects Aug 01 '20 at 14:17
Let me demonstrate with a piece of code taken from an answer to a "functional" Python question on SO
Python:
def grandKids(generation, kidsFunc, val):
layer = [val]
for i in xrange(generation):
layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer))
return layer
Haskell:
grandKids generation kidsFunc val =
iterate (concatMap kidsFunc) [val] !! generation
The main difference here is that Haskell's standard library has useful functions for functional programming: in this case iterate
, concat
, and (!!)
-
8Here's a one-line replacement for `grandKids()` body with generator expressions: `return reduce(lambda a, v: concat((x for x in kidsFunc(v)) for v in a), xrange(generation), [val])`. – Lloeki Oct 22 '11 at 16:15
-
7And here's one which does not need `concat` either: `return reduce(lambda a, v: (x for v in a for x in kidsFunc(v)), xrange(generation), [val])` – Lloeki Oct 22 '11 at 16:24
-
9@Lloeki: iterate would simplify that code significantly, and (x for v in a for x in kidsFunc(v)) is much clearer as concatMap(kidsFunc). Python's lack of nice higher-order builtins makes equivalent code cryptic and verbose compared to Haskell. – Phob Sep 14 '12 at 00:30
-
2
One thing that is really important for this question (and the answers) is the following: What the hell is functional programming, and what are the most important properties of it. I'll try to give my view of it:
Functional programming is a lot like writing math on a whiteboard. When you write equations on a whiteboard, you do not think about an execution order. There is (typically) no mutation. You don't come back the day after and look at it, and when you make the calculations again, you get a different result (or you may, if you've had some fresh coffee :)). Basically, what is on the board is there, and the answer was already there when you started writing things down, you just haven't realized what it is yet.
Functional programming is a lot like that; you don't change things, you just evaluate the equation (or in this case, "program") and figure out what the answer is. The program is still there, unmodified. The same with the data.
I would rank the following as the most important features of functional programming: a) referential transparency - if you evaluate the same statement at some other time and place, but with the same variable values, it will still mean the same. b) no side effect - no matter how long you stare at the whiteboard, the equation another guy is looking at at another whiteboard won't accidentally change. c) functions are values too. which can be passed around and applied with, or to, other variables. d) function composition, you can do h=g·f and thus define a new function h(..) which is equivalent to calling g(f(..)).
This list is in my prioritized order, so referential transparency is the most important, followed by no side effects.
Now, if you go through python and check how well the language and libraries supports, and guarantees, these aspects - then you are well on the way to answer your own question.

- 392
- 2
- 5
-
2
-
-
1I don't think Python is a good language for functional programming. I'm not even sure now what I meant by that comment to be honest. It doesn't seem relevant to the answer. I would delete it, but then your comment would be out of context. – Carl Smith Feb 08 '16 at 14:06
-
1Referential transparency and immutability aren't really language features. Yes, some languages (Haskell) emphasize them and make it hard to not have them, but you can make a referentially transparent function or an immutable object in essentially any language. You just have to work around the standard library, which will often violate them. – Kevin Jun 30 '16 at 15:10
-
Also, Python has support for both currying and composition, but not at the language level, it's in the standard library instead. – Kevin Jun 30 '16 at 15:11
-
The _impossibility_ of side effects _is_ a feature of purely functional languages. It guarantees referential transparency, and makes various refactorings & optimizations definitely safe, instead of "programmer's job to figure if it's safe in specific situation". It makes lazyness safe. Yes you can write a functional subset in other languages, but you won't get the same flavor of data & libraries unless it's a guarantee you can rely on. – Beni Cherniavsky-Paskin Dec 15 '20 at 13:47
Python is almost a functional language. It's "functional lite".
It has extra features, so it isn't pure enough for some.
It also lacks some features, so it isn't complete enough for some.
The missing features are relatively easy to write. Check out posts like this on FP in Python.
-
2For the most part, I agree with this post. But I can't agree with saying that Python is a functional language. It very much encourages imperative programming, and it's difficult not to with the "extra features" you mention. I think it's best to refer to Python as "functional lite" as you did in the other post. :-) – Jason Baker Jun 19 '09 at 14:00
-
8-1 Sorry, no. I mean, just, no. Functional languages provide constructs that facilitate formal reasoning: inductive (ML), equational (Haskell). Closures and anonymous functions alone are just syntactic sugar for the strategy pattern. – isekaijin Dec 09 '13 at 02:42
Another reason not mentioned above is that many built-in functions and methods of built-in types modify an object but do not return the modified object. If those modified objects were returned, that would make functional code cleaner and more concise. For example, if some_list.append(some_object) returned some_list with some_object appended.

- 438
- 5
- 10
-
`append()` and `extend()` not returning the original list is a headache that keeps on giving – WestCoastProjects Aug 01 '20 at 14:07
In addition to other answers, one reason Python and most other multi-paradigm languages are not well suited for true functional programming is because their compilers / virtual machines / run-times do not support functional optimization. This sort of optimization is achieved by the compiler understanding mathematical rules. For example, many programming languages support a map
function or method. This is a fairly standard function that takes a function as one argument and a iterable as the second argument then applies that function to each element in the iterable.
Anyways it turns out that map( foo() , x ) * map( foo(), y )
is the same as map( foo(), x * y )
. The latter case is actually faster than the former because the former performs two copies where the latter performs one.
Better functional languages recognize these mathematically based relationships and automatically perform the optimization. Languages that aren't dedicated to the functional paradigm will likely not optimize.
-
`map( foo() , x ) * map( foo(), y ) == map( foo(), x * y )` is not true for all functions. For example, consider the case when `foo` calculates a derivative. – Eli Korvigo Jul 29 '16 at 11:15
-
1
-
-
that property is NOT true for foo(x) = x+1. As (x+1)*(y+1) != x*y + 1. – juan Isaza Jan 03 '18 at 13:57