Sadly, Python is a pretty poor functional language.
The core of functional programming is about avoiding mutable states, not much about anonymous functions or passing functions as data.
To do proper functional programming in Python, there should be IMO:
- a way to enforce non-mutable variables/objects;
- non-mutable collections;
- proper support for recursion and tail-recursion optimization;
- a better syntax for anonymous functions than single statement lambdas.
Generators are nice, but do not have much to do with functional programming.
shameless plug: I maintain a small library to do functional pipes.
You can write:
( range(10) | Map(lambda x: x * 10) | Filter(lambda x: x % 2 == 0) | Reduce(lambda a, b: a + b) )
and more. https://tandav.github.io/pipe21/
x = range(10) x = map(lambda x: x * 10, x) x = filter(lambda x: x % 2 == 0, x) x = reduce(lambda a, b: a + b, x)
I thought I knew functional programming from knowing Python, but looking back I didn't really "grok" it until I moved to Elixir. Now I like it and prefer it. I don't run into any of the types of bugs I used to create in Python, mostly from being lazy and fiddling with data inside of a loop. I miss do miss early returns though.
Thanks for posting this. Many years ago (2006?) I was a just-out-of-university programmer and a friend of a friend who wrote Python for Canonical sat me down and tried to teach me functional programming using Python. I was a poor learner: I didn't 'get it' (functional programming in general) and, to my regret, learned nothing.
Much time has passed and I hope I'm a more aware and open-to-new-things person today :) I use Python these days though in a traditional procedural / OO way. This post reminded me that maybe I should look into writing it functional-style. Thankyou!
Shameless plug for Scala programmers who are marooned in Python land and grasping for something to help dig them out: https://github.com/miiohio/ziopy
Fun to work on doing FP in languages that don't really support it, but in my view a language has to be built for FP for it to be a practical option in any real applications. Several obvious reasons for Python being a poor lang in which to do FP:
Still, a fun project!
- mutable data structures - no built-in function composition - limited support for HOF - no tail call optimization (AFAIK) - performance in general isn't great and I imagine it's even worse when relying heavily on recursion, etc
Iterators are a fundamentally non-functional construct. Long ago Henry Baker wrote "Signs of Weakness in Object-Oriented Languages": https://plover.com/~mjd/misc/hbaker-archive/Iterator.html
For those who are interest I maintain a small open source library to use type safe monads in python https://github.com/sammyrulez/typed-monads
In their definition of programming languages types, I'm not sure I see how SQL which they cateogrize as declarative really differs from FP, especially with lazy evaluation. Both are a succession of functions applied onto a previously declared variable : just think of a long SQL query with many ctes modifying the previous ones; each of them can be thought of as a variable which takes its value from the application of a function on other variable (a bit like the let function in ocaml).
I always thought of LaTeX as being the prime example of declarative programming.
How new is this? Seems like there is more functional tools in Python than I remember. Didn't see the new 'match' statement in this doc.
I tried to preach functional programming style to my data analysts colleagues once... it ended poorly, but it was fun!
If you want to smile, here is the presentation I made (warn: old memes ahead)
What's so useful about iterators and generators. The article says how to use them but not why. If you already know how to make list comprehensions and use "for elt in coll", do they let you do anything new?
can you make anonymous functions with more than 1 expression now?
What blows my mind is that Python was designed for maths and data science by a maths and data science guy. It should be natural to work with immutable values and pipelines in Python, which are natural functional constructs. Yet everything in Python is mutable and pipeline-style programming is not really supported. ???
(A long time ago I tried to teach programming fundamentals to a maths person. She was completely puzzled by x=x+1. X equals to X+1? That was nonsense in their eyes.)
@dataclass is the new final
Worthless functionality in a worthless language. Only topped by the bizarre and unverified claims in its documentation:
Did the author count? -- The answer is a clear and resounding "No". The author pulled this factoid out if his rear end. Maybe. Maybe not. It's not even clear by what's meant by "all languages" -- all possible languages? all languages known to author? all languages used in Github? And why should anyone care about this kind of multitude?
Most programming languages are procedural:
Again, people who've never seen any Lisp, or vaguely remember their college days when some course requested from them to write a function to figure out if a string is a palindrome in Scheme think that Lisp is a single language. The author just decided to demonstrate his blistering ignorance by including something that he thought would render him as more experienced than their readers.
Later the author perpetuates all sorts of absurd myths about "functional programming" s.a. increased modularity or ease of debugging. Apparently, author had never used step-debugger nor had he wrote anything in any popular programming language that advertises itself as functional to experience first-hand this "ease" he's talking about. Needless to say that nothing in functional programming prevents programmers from writing long functions... In practice, however, some languages which advertise themselves as "functional" have pathologically bad / hard to read syntax (eg. Haskell), and functions longer than some 10 lines or so become too difficult to understand even to people who believe themselves to be proficient in those languages.
Author is simply lying when he claims that generators are a kind of function, which can be simply verified:
Generators and functions are unrelated. Neither is a kind of other.
>>> def generate_ints(n): ... for i in range(n): ... yield i ... >>> type(generate_ints(1)) <class 'generator'> >>> type(generate_ints(1)).mro() [<class 'generator'>, <class 'object'>] >>> isinstance(generate_ints(1), type(generate_ints)) False
On top of that, author frequently violates Python's coding conventions (eg. capital letters in variable names, assigning lambdas to variables).
But, bottom line: crappy language deserves no better documentation than this.